From 9162eec91dd48d26268f06f920ec0c912773d834 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 27 Jul 2020 03:52:46 +0200 Subject: [PATCH 01/91] 1) modified PrimitiveOp._check_zero_for_composition_and_expand, so that it expands shorter operator with identity 2) implemented OperatorBase.expand 3) defined abstract method OperatorBase.identity, and implemented in child classes of OperatorBase (TODO check if implementation makes sense for every class) 4) created tests for composing Operators of different dimensions --- .../aqua/operators/evolutions/evolved_op.py | 8 ++++- qiskit/aqua/operators/list_ops/list_op.py | 13 +++++++++ qiskit/aqua/operators/operator_base.py | 16 ++++++++++ .../operators/primitive_ops/circuit_op.py | 13 +++++++-- .../aqua/operators/primitive_ops/matrix_op.py | 6 +++- .../aqua/operators/primitive_ops/pauli_op.py | 6 +++- .../operators/primitive_ops/primitive_op.py | 16 +++++----- .../operators/state_fns/circuit_state_fn.py | 6 ++++ .../aqua/operators/state_fns/dict_state_fn.py | 3 ++ .../operators/state_fns/operator_state_fn.py | 3 ++ .../operators/state_fns/vector_state_fn.py | 4 +++ test/aqua/operators/test_op_construction.py | 29 ++++++++++++++++++- 12 files changed, 110 insertions(+), 13 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index f8ee309f4f..0f5845875e 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -20,10 +20,12 @@ import scipy from qiskit.circuit import ParameterExpression, Instruction +from qiskit.quantum_info import Pauli from ..operator_base import OperatorBase from ..primitive_ops.primitive_op import PrimitiveOp from ..primitive_ops.matrix_op import MatrixOp +from ..primitive_ops.pauli_op import PauliOp from ..list_ops import ListOp from ..list_ops.summed_op import SummedOp from ..list_ops.composed_op import ComposedOp @@ -88,8 +90,12 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) + @staticmethod + def identity(dim: int) -> OperatorBase: + return PauliOp.identity(dim) + def compose(self, other: OperatorBase) -> OperatorBase: - other = self._check_zero_for_composition_and_expand(other) + self, other = self._check_zero_for_composition_and_expand(other) if isinstance(other, ComposedOp): return ComposedOp([self] + other.oplist) # type: ignore diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index d171e8cbf2..a3a7390446 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -21,6 +21,8 @@ from scipy.sparse import spmatrix from qiskit.circuit import ParameterExpression +from qiskit.quantum_info import Pauli + from ..legacy.base_operator import LegacyBaseOperator from ..operator_base import OperatorBase @@ -173,6 +175,17 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat coeff=self.coeff * scalar, abelian=self.abelian) + def identity(self, num_qubit: int) -> OperatorBase: + """Returns the PauliOp, with Pauli I as primitive.. + Choice of Pauli as identity is arbitrary and could be substituted + for other PrimitiveOp.identity. + Returns: + identity operator represented by Pauli(label='I'*num_qubit) + """ + from qiskit.aqua.operators import PauliOp + primitive = Pauli(label='I' * num_qubit) + return PauliOp(primitive) + def tensor(self, other: OperatorBase) -> OperatorBase: # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 9899dfd9ed..ac8f56f86e 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -370,6 +370,14 @@ def __rxor__(self, other: Union['OperatorBase', int]) -> 'OperatorBase': else: return cast(OperatorBase, other).tensor(self) + @abstractmethod + def identity(self, dim: int) -> 'OperatorBase': + """ + Returns: + identity operator of dimension 'dim'. + """ + raise NotImplementedError + @abstractmethod def tensor(self, other: 'OperatorBase') -> 'OperatorBase': r""" Return tensor product between self and other, overloaded by ``^``. @@ -431,6 +439,14 @@ def assign_parameters(self, """ raise NotImplementedError + def expand(self, num_qubits: int) -> 'OperatorBase': + """Expand the operator with identity operator of dimension corresponding to num_qubits. + Returns: + Operator corresponding to self.tensor(identity_operator), where dimension of + identity operator is 2 ^ num_qubits. + """ + return self.tensor(self.identity(num_qubits)) + def bind_parameters(self, param_dict: Dict[ParameterExpression, Union[Number, diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 46ed322fe5..d15428718f 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -111,7 +111,7 @@ 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) + self, other = self._check_zero_for_composition_and_expand(other) # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero from ..state_fns import CircuitStateFn @@ -214,6 +214,9 @@ def to_circuit_op(self) -> OperatorBase: def to_instruction(self) -> Instruction: return self.primitive.to_instruction() # type: ignore + def to_circuit_state_fn(self, is_measurement=False) -> OperatorBase: + return + # Warning - modifying immutable object!! def reduce(self) -> OperatorBase: if self.primitive.data is not None: # type: ignore @@ -228,6 +231,12 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] # type: ignore return self + def identity(self, num_qubits: int) -> OperatorBase: + new_qc = QuantumCircuit(num_qubits) + for i in range(num_qubits): + new_qc.i(i) + return CircuitOp(new_qc) + def permute(self, permutation: List[int]) -> 'CircuitOp': r""" Permute the qubits of the circuit. @@ -239,5 +248,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) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index a69a5c1c07..122f0fc545 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -116,7 +116,7 @@ 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) + self, other = self._check_zero_for_composition_and_expand(other) if isinstance(other, MatrixOp): return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore @@ -124,6 +124,10 @@ def compose(self, other: OperatorBase) -> OperatorBase: return ComposedOp([self, other]) + def identity(self, num_qubits: int) -> OperatorBase: + identity = np.identity(2**num_qubits, dtype=complex) + return MatrixOp(Operator(identity)) + def to_matrix(self, massive: bool = False) -> np.ndarray: return self.primitive.data * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 1cbcb22b6f..29d2643a86 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -98,8 +98,12 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) + def identity(self, num_qubit: int) -> OperatorBase: + primitive = Pauli(label='I'*num_qubit) + return PauliOp(primitive) + def compose(self, other: OperatorBase) -> OperatorBase: - other = self._check_zero_for_composition_and_expand(other) + self, other = self._check_zero_for_composition_and_expand(other) # If self is identity, just return other. if not any(self.primitive.x + self.primitive.z): # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 08fe9451c2..c19577f735 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -14,7 +14,7 @@ """ PrimitiveOp Class """ -from typing import Optional, Union, Set, List +from typing import Optional, Union, Set, List, Tuple import logging import numpy as np from scipy.sparse import spmatrix @@ -158,18 +158,20 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: def compose(self, other: OperatorBase) -> OperatorBase: raise NotImplementedError - def _check_zero_for_composition_and_expand(self, other: OperatorBase) -> OperatorBase: + def _check_zero_for_composition_and_expand(self, other: OperatorBase) \ + -> Tuple[OperatorBase, OperatorBase]: + new_self = self 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) - else: - raise ValueError( - 'Composition is not defined over Operators of different dimensions, {} and {}, ' - 'respectively.'.format(self.num_qubits, other.num_qubits)) - return other + elif other.num_qubits < self.num_qubits: + other = other.expand(self.num_qubits - other.num_qubits) + elif other.num_qubits > self.num_qubits: + new_self = self.expand(other.num_qubits - self.num_qubits) + return new_self, other def power(self, exponent: int) -> OperatorBase: if not isinstance(exponent, int) or exponent <= 0: diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index eed5b5e7f5..26874af222 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -170,6 +170,12 @@ def compose(self, other: OperatorBase) -> OperatorBase: from qiskit.aqua.operators import ComposedOp return ComposedOp([new_self, other]) + def identity(self, dim: int) -> 'CircuitStateFn': + new_qc = QuantumCircuit(dim) + for i in range(dim): + new_qc.i(i) + return CircuitStateFn(new_qc, is_measurement=self.is_measurement) + def tensor(self, other: OperatorBase) -> OperatorBase: r""" Return tensor product between self and other, overloaded by ``^``. diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 99ad5550da..c30599ca19 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -109,6 +109,9 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) + def identity(self, num_qubits: int) -> 'DictStateFn': + return DictStateFn('0' * num_qubits, is_measurement=self.is_measurement) + def tensor(self, other: OperatorBase) -> OperatorBase: # Both dicts if isinstance(other, DictStateFn): diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index 507f733966..6d82e08db4 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -82,6 +82,9 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) + def identity(self, num_qubits: int) -> 'OperatorStateFn': + return OperatorStateFn(self.primitive.identity(num_qubits)) + def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, OperatorStateFn): return StateFn(self.primitive.tensor(other.primitive), diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 8e9bf85c6f..6744930c3e 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -78,6 +78,10 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) + def identity(self, num_qubits: int) -> 'VectorStateFn': + primitive = np.identity(2**num_qubits, dtype=complex) + return VectorStateFn(primitive) + def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, VectorStateFn): return StateFn(self.primitive.tensor(other.primitive), diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index ade261db0a..9db2f793e6 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -27,7 +27,8 @@ from qiskit.circuit.library import CZGate, ZGate from qiskit.aqua.operators import ( - X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp, MatrixOp + X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp, MatrixOp, + CircuitStateFn, VectorStateFn, DictStateFn, OperatorStateFn ) @@ -344,6 +345,32 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'ZZ']) self.assertListEqual([op.coeff for op in sum_op], [10, 2, 3]) + def test_compose_op_of_different_dim(self): + # PauliOps of different dim + xy_p = (X ^ Y) + xyz_p = (X ^ Y ^ Z) + + pauli_op = xy_p @ xyz_p + expected_result = (I ^ I ^ Z) + self.assertEqual(pauli_op, expected_result) + + # MatrixOps of different dim + xy_m = xy_p.to_matrix_op() + xyz_m = xyz_p.to_matrix_op() + + matrix_op = xy_m @ xyz_m + self.assertEqual(matrix_op, expected_result.to_matrix_op()) + + # CircuitOps of different dim + xy_c = xy_p.to_circuit_op() + xyz_c = xyz_p.to_circuit_op() + + circuit_op = xy_c @ xyz_c + + self.assertTrue(np.array_equal(pauli_op.to_matrix(), matrix_op.to_matrix())) + self.assertTrue(np.allclose(pauli_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) + self.assertTrue(np.allclose(matrix_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) + def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" with self.subTest('multiplicative factor'): From 5ff3d650130617975fe595c314fc62324f65a623 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 27 Jul 2020 04:21:00 +0200 Subject: [PATCH 02/91] CircuitStateFn.tensor did not set is_measurement parameter (hence always default to False), even if tensored instances were is_measurement=True --- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 26874af222..408fc2e459 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -202,7 +202,10 @@ def tensor(self, other: OperatorBase) -> OperatorBase: from ..operator_globals import Zero c_op_self = CircuitOp(self.primitive, self.coeff) c_op_other = CircuitOp(other.primitive, other.coeff) - return c_op_self.tensor(c_op_other).compose(Zero) + c_op = c_op_self.tensor(c_op_other) + if isinstance(c_op, CircuitOp): + return CircuitStateFn(primitive=c_op.primitive, coeff=c_op.coeff, + is_measurement=self.is_measurement) # pylint: disable=cyclic-import from ..list_ops.tensored_op import TensoredOp return TensoredOp([self, other]) From 95ad4889f353324c4a62962fe1b2c83c5da71934 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 27 Jul 2020 05:56:46 +0200 Subject: [PATCH 03/91] Added test for expand method on StateFn subclasses --- .../operators/state_fns/vector_state_fn.py | 2 +- test/aqua/operators/test_op_construction.py | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 6744930c3e..a6174b5817 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -79,7 +79,7 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def identity(self, num_qubits: int) -> 'VectorStateFn': - primitive = np.identity(2**num_qubits, dtype=complex) + primitive = np.zeros(2**num_qubits, dtype=complex) return VectorStateFn(primitive) def tensor(self, other: OperatorBase) -> OperatorBase: diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 9db2f793e6..2ef2fa1b8d 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -371,6 +371,40 @@ def test_compose_op_of_different_dim(self): self.assertTrue(np.allclose(pauli_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) self.assertTrue(np.allclose(matrix_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) + def test_expand_on_state_fn(self): + """ Tests num_qubits on the original instance and expanded instance of StateFn """ + num_qubits = 3 + add_qubits = 2 + + # case CircuitStateFn, with primitive QuantumCircuit + qc2 = QuantumCircuit(num_qubits) + qc2.cx(0, 1) + + cfn = CircuitStateFn(qc2, is_measurement=True) + + cfn_exp = cfn.expand(add_qubits) + self.assertEqual(cfn_exp.num_qubits, add_qubits + num_qubits) + + # case OperatorStateFn, with OperatorBase primitive, in our case CircuitStateFn + osfn = OperatorStateFn(cfn) + osfn_exp = osfn.expand(add_qubits) + + self.assertEqual(osfn_exp.num_qubits, add_qubits + num_qubits) + + # case DictStateFn + dsfn = DictStateFn('1'*num_qubits, is_measurement=True) + self.assertEqual(dsfn.num_qubits, num_qubits) + + dsfn_exp = dsfn.expand(add_qubits) + self.assertEqual(dsfn_exp.num_qubits, num_qubits + add_qubits) + + # case VectorStateFn + vsfn = VectorStateFn(np.ones(2**num_qubits, dtype=complex)) + self.assertEqual(vsfn.num_qubits, num_qubits) + + vsfn_exp = vsfn.expand(add_qubits) + self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits) + def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" with self.subTest('multiplicative factor'): From cb6a709d1dffd3ee4531940185aece203e714304 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 27 Jul 2020 08:42:28 +0200 Subject: [PATCH 04/91] fixed linting --- qiskit/aqua/operators/evolutions/evolved_op.py | 10 +++++----- qiskit/aqua/operators/list_ops/list_op.py | 4 ++-- qiskit/aqua/operators/operator_base.py | 2 +- qiskit/aqua/operators/primitive_ops/circuit_op.py | 3 --- qiskit/aqua/operators/primitive_ops/pauli_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/primitive_op.py | 3 +++ qiskit/aqua/operators/state_fns/circuit_state_fn.py | 7 +++---- qiskit/aqua/operators/state_fns/state_fn.py | 3 +++ test/aqua/operators/test_op_construction.py | 4 ++++ 9 files changed, 23 insertions(+), 17 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 0f5845875e..6d4d73a72f 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -20,12 +20,10 @@ import scipy from qiskit.circuit import ParameterExpression, Instruction -from qiskit.quantum_info import Pauli from ..operator_base import OperatorBase from ..primitive_ops.primitive_op import PrimitiveOp from ..primitive_ops.matrix_op import MatrixOp -from ..primitive_ops.pauli_op import PauliOp from ..list_ops import ListOp from ..list_ops.summed_op import SummedOp from ..list_ops.composed_op import ComposedOp @@ -90,9 +88,11 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - @staticmethod - def identity(dim: int) -> OperatorBase: - return PauliOp.identity(dim) + def identity(self, num_qubits: int) -> OperatorBase: + from ..primitive_ops.pauli_op import PauliOp + from qiskit.quantum_info import Pauli + primitive = Pauli(label='I' * num_qubits) + return PauliOp(primitive) def compose(self, other: OperatorBase) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index a3a7390446..e2c7413d55 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -175,7 +175,7 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat coeff=self.coeff * scalar, abelian=self.abelian) - def identity(self, num_qubit: int) -> OperatorBase: + def identity(self, num_qubits: int) -> OperatorBase: """Returns the PauliOp, with Pauli I as primitive.. Choice of Pauli as identity is arbitrary and could be substituted for other PrimitiveOp.identity. @@ -183,7 +183,7 @@ def identity(self, num_qubit: int) -> OperatorBase: identity operator represented by Pauli(label='I'*num_qubit) """ from qiskit.aqua.operators import PauliOp - primitive = Pauli(label='I' * num_qubit) + primitive = Pauli(label='I' * num_qubits) return PauliOp(primitive) def tensor(self, other: OperatorBase) -> OperatorBase: diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index ac8f56f86e..ee661ade71 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -371,7 +371,7 @@ def __rxor__(self, other: Union['OperatorBase', int]) -> 'OperatorBase': return cast(OperatorBase, other).tensor(self) @abstractmethod - def identity(self, dim: int) -> 'OperatorBase': + def identity(self, num_qubits: int) -> 'OperatorBase': """ Returns: identity operator of dimension 'dim'. diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index d15428718f..2f5787fbc9 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -214,9 +214,6 @@ def to_circuit_op(self) -> OperatorBase: def to_instruction(self) -> Instruction: return self.primitive.to_instruction() # type: ignore - def to_circuit_state_fn(self, is_measurement=False) -> OperatorBase: - return - # Warning - modifying immutable object!! def reduce(self) -> OperatorBase: if self.primitive.data is not None: # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 29d2643a86..e9dac401b7 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -98,8 +98,8 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def identity(self, num_qubit: int) -> OperatorBase: - primitive = Pauli(label='I'*num_qubit) + def identity(self, num_qubits: int) -> OperatorBase: + primitive = Pauli(label='I'*num_qubits) return PauliOp(primitive) def compose(self, other: OperatorBase) -> OperatorBase: diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index c19577f735..beb7c75a3e 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -155,6 +155,9 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp + def identity(self, num_qubits: int) -> 'PrimitiveOp': + raise NotImplementedError + def compose(self, other: OperatorBase) -> OperatorBase: raise NotImplementedError diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 408fc2e459..67e62dd1e3 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -170,9 +170,9 @@ def compose(self, other: OperatorBase) -> OperatorBase: from qiskit.aqua.operators import ComposedOp return ComposedOp([new_self, other]) - def identity(self, dim: int) -> 'CircuitStateFn': - new_qc = QuantumCircuit(dim) - for i in range(dim): + def identity(self, num_qubits: int) -> 'CircuitStateFn': + new_qc = QuantumCircuit(num_qubits) + for i in range(num_qubits): new_qc.i(i) return CircuitStateFn(new_qc, is_measurement=self.is_measurement) @@ -199,7 +199,6 @@ def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, CircuitStateFn) and other.is_measurement == self.is_measurement: # Avoid reimplementing tensor, just use CircuitOp's from ..primitive_ops.circuit_op import CircuitOp - from ..operator_globals import Zero c_op_self = CircuitOp(self.primitive, self.coeff) c_op_other = CircuitOp(other.primitive, other.coeff) c_op = c_op_self.tensor(c_op_other) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 6ff880a07e..848bf21db8 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -158,6 +158,9 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat coeff=self.coeff * scalar, is_measurement=self.is_measurement) + def identity(self, num_qubits: int) -> 'StateFn': + raise NotImplementedError + def tensor(self, other: OperatorBase) -> OperatorBase: r""" Return tensor product between self and other, overloaded by ``^``. diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 2ef2fa1b8d..4c5d611734 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -346,6 +346,10 @@ def test_summed_op_reduce(self): self.assertListEqual([op.coeff for op in sum_op], [10, 2, 3]) def test_compose_op_of_different_dim(self): + """ + Test if smaller operator expands to correct dim when composed with bigger operator. + Test if compose methods of PrimitiveOp types are consistent. + """ # PauliOps of different dim xy_p = (X ^ Y) xyz_p = (X ^ Y ^ Z) From f7ef9099511706f4bf61b987bae471e07ef413c2 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 27 Jul 2020 21:35:13 +0200 Subject: [PATCH 05/91] fixed linting and mypy --- qiskit/aqua/operators/evolutions/evolved_op.py | 6 +++--- qiskit/aqua/operators/primitive_ops/circuit_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/matrix_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/pauli_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/primitive_op.py | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 6d4d73a72f..eebe95d8a3 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -24,6 +24,7 @@ from ..operator_base import OperatorBase from ..primitive_ops.primitive_op import PrimitiveOp from ..primitive_ops.matrix_op import MatrixOp +from ..primitive_ops.pauli_op import PauliOp # pylint: disable=cyclic-import from ..list_ops import ListOp from ..list_ops.summed_op import SummedOp from ..list_ops.composed_op import ComposedOp @@ -88,14 +89,13 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def identity(self, num_qubits: int) -> OperatorBase: - from ..primitive_ops.pauli_op import PauliOp + def identity(self, num_qubits: int) -> 'PrimitiveOp': from qiskit.quantum_info import Pauli primitive = Pauli(label='I' * num_qubits) return PauliOp(primitive) def compose(self, other: OperatorBase) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other) + self, other = self._check_zero_for_composition_and_expand(other) # type: ignore if isinstance(other, ComposedOp): return ComposedOp([self] + other.oplist) # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 2f5787fbc9..4c53f9af68 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -111,7 +111,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other) + self, other = self._check_zero_for_composition_and_expand(other) # type: ignore # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero from ..state_fns import CircuitStateFn @@ -228,7 +228,7 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] # type: ignore return self - def identity(self, num_qubits: int) -> OperatorBase: + def identity(self, num_qubits: int) -> 'CircuitOp': new_qc = QuantumCircuit(num_qubits) for i in range(num_qubits): new_qc.i(i) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 122f0fc545..fad46528c3 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -116,7 +116,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other) + self, other = self._check_zero_for_composition_and_expand(other) # type: ignore if isinstance(other, MatrixOp): return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore @@ -124,7 +124,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: return ComposedOp([self, other]) - def identity(self, num_qubits: int) -> OperatorBase: + def identity(self, num_qubits: int) -> 'MatrixOp': identity = np.identity(2**num_qubits, dtype=complex) return MatrixOp(Operator(identity)) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index e9dac401b7..f1754c26ee 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -98,12 +98,12 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def identity(self, num_qubits: int) -> OperatorBase: + def identity(self, num_qubits: int) -> 'PauliOp': primitive = Pauli(label='I'*num_qubits) return PauliOp(primitive) def compose(self, other: OperatorBase) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other) + self, other = self._check_zero_for_composition_and_expand(other) # type: ignore # If self is identity, just return other. if not any(self.primitive.x + self.primitive.z): # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index beb7c75a3e..4c417c187f 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -162,7 +162,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: raise NotImplementedError def _check_zero_for_composition_and_expand(self, other: OperatorBase) \ - -> Tuple[OperatorBase, OperatorBase]: + -> Tuple['PrimitiveOp', OperatorBase]: new_self = self if not self.num_qubits == other.num_qubits: # pylint: disable=cyclic-import,import-outside-toplevel @@ -173,7 +173,7 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase) \ elif other.num_qubits < self.num_qubits: other = other.expand(self.num_qubits - other.num_qubits) elif other.num_qubits > self.num_qubits: - new_self = self.expand(other.num_qubits - self.num_qubits) + new_self = self.expand(other.num_qubits - self.num_qubits) # type: ignore return new_self, other def power(self, exponent: int) -> OperatorBase: From 804054e6f557b9dbad567657ff265784aae7d885 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 27 Jul 2020 22:04:45 +0200 Subject: [PATCH 06/91] fixed unexpected indentation --- qiskit/aqua/operators/operator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index ee661ade71..9274d2e2fe 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -440,7 +440,7 @@ def assign_parameters(self, raise NotImplementedError def expand(self, num_qubits: int) -> 'OperatorBase': - """Expand the operator with identity operator of dimension corresponding to num_qubits. + """ Expand the operator with identity operator of dimension corresponding to num_qubits. Returns: Operator corresponding to self.tensor(identity_operator), where dimension of identity operator is 2 ^ num_qubits. From 0c831f9cce1d04e85a6ede6eeeaa41860643ed20 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 29 Jul 2020 15:44:15 +0200 Subject: [PATCH 07/91] 1) PauliOp.permute implemented 2) test_permute_on_primitive_op implemented. It checks correctness and consistency of permute implementations. --- .../aqua/operators/primitive_ops/pauli_op.py | 23 ++++++++++++++++++- test/aqua/operators/test_op_construction.py | 19 +++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index f1754c26ee..0da3ca0836 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -14,7 +14,7 @@ """ PauliOp Class """ -from typing import Union, Set, Dict, cast +from typing import Union, Set, Dict, cast, List import logging import numpy as np from scipy.sparse import spmatrix @@ -30,6 +30,7 @@ from ..list_ops.composed_op import ComposedOp from ..list_ops.tensored_op import TensoredOp from ..legacy.weighted_pauli_operator import WeightedPauliOperator +from ... import AquaError logger = logging.getLogger(__name__) PAULI_GATE_MAPPING = {'X': XGate(), 'Y': YGate(), 'Z': ZGate(), 'I': IGate()} @@ -98,6 +99,26 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) + def permute(self, indices: List[int] = None) -> 'PauliOp': + """ Permutes the underlying Pauli matrices. + Args: + indices: A list defining where each Pauli should be permuted. The Pauli at index + j of the primitive should be permuted to position indices[j]. + Returns: + A new PauliOp with the permuted Paulis. For operator (X ^ Y ^ Z) and indices=[1,2,4], + it returns (X ^ I ^ Y ^ Z ^ I). + Raises: + AquaError: if number of indices to not match the num_qubits + """ + pauli_string = self.primitive.__str__() + length = max(indices) + 1 # size of list must be +1 larger then its max index + new_pauli_list = ['I'] * length + if len(indices) != self.num_qubits: + raise AquaError("List of indices to permute must have the same size as Pauli Operator") + for i, index in enumerate(indices): + new_pauli_list[-index - 1] = pauli_string[-i - 1] + return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) + def identity(self, num_qubits: int) -> 'PauliOp': primitive = Pauli(label='I'*num_qubits) return PauliOp(primitive) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 4c5d611734..1541d089e9 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -375,6 +375,25 @@ def test_compose_op_of_different_dim(self): self.assertTrue(np.allclose(pauli_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) self.assertTrue(np.allclose(matrix_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) + def test_permute_on_primitive_op(self): + """ Test if permute methods of PrimitiveOps are consistent and work correctly. """ + indices = [1, 2, 4] + + # PauliOp + pauli_op = (X ^ Y ^ Z) + permuted_pauli_op = pauli_op.permute(indices) + expected_pauli_op = (X ^ I ^ Y ^ Z ^ I) + + self.assertEqual(permuted_pauli_op, expected_pauli_op) + + # CircuitOp + circuit_op = pauli_op.to_circuit_op() + permuted_circuit_op = circuit_op.permute(indices) + expected_circuit_op = expected_pauli_op.to_circuit_op() + + self.assertEqual(permuted_circuit_op.primitive.__str__(), + expected_circuit_op.primitive.__str__()) + def test_expand_on_state_fn(self): """ Tests num_qubits on the original instance and expanded instance of StateFn """ num_qubits = 3 From a4e7114e9caf2fc39e1fbaa5d2f0c881685f53c7 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 3 Aug 2020 12:20:12 +0200 Subject: [PATCH 08/91] 1) permute implemented for MatrixOp 2) added testcase for MatrixOp permute, to check consistency with PauliOp.permute and CircuitOp.permute --- .../aqua/operators/primitive_ops/matrix_op.py | 26 ++++++++++++++++++- test/aqua/operators/test_op_construction.py | 8 ++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index fad46528c3..f87d6aaf32 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -14,10 +14,12 @@ """ MatrixOp Class """ -from typing import Union, Optional, Set +from typing import Union, Optional, Set, List import logging import numpy as np +from qiskit import QuantumCircuit from scipy.sparse import spmatrix +from sympy.combinatorics import Permutation from qiskit.quantum_info import Operator from qiskit.circuit import ParameterExpression, Instruction @@ -30,6 +32,7 @@ from ..list_ops.tensored_op import TensoredOp from .primitive_op import PrimitiveOp from ..legacy.matrix_operator import MatrixOperator +from ... import AquaError logger = logging.getLogger(__name__) @@ -124,6 +127,27 @@ def compose(self, other: OperatorBase) -> OperatorBase: return ComposedOp([self, other]) + def permute(self, indices: List[int] = None): + new_self = self + new_matrix_size = max(indices) + 1 + + # extend the indices to match the size of the new matrix + indices = list(filter(lambda x: x not in indices, range(new_matrix_size))) + indices + + if self.num_qubits > len(indices): + raise AquaError("New index must be defined for each qubit of the operator.") + if self.num_qubits < new_matrix_size: + # pad the operator with identities + new_self = self.expand(new_matrix_size - self.num_qubits) + qc = QuantumCircuit(new_matrix_size) + + # decompose permutation into sequence of transpositions + transpositions = Permutation(indices).transpositions() + for t in transpositions: + qc.swap(t[0], t[1]) + matrix = CircuitOp(qc).to_matrix() + return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # permuted MatrixOp + def identity(self, num_qubits: int) -> 'MatrixOp': identity = np.identity(2**num_qubits, dtype=complex) return MatrixOp(Operator(identity)) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 1541d089e9..5ce5b87959 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -394,6 +394,14 @@ def test_permute_on_primitive_op(self): self.assertEqual(permuted_circuit_op.primitive.__str__(), expected_circuit_op.primitive.__str__()) + # MatrixOp + matrix_op = pauli_op.to_matrix_op() + permuted_matrix_op = matrix_op.permute(indices) + expected_matrix_op = expected_pauli_op.to_matrix_op() + + equal = np.allclose(permuted_matrix_op.to_matrix(), expected_matrix_op.to_matrix()) + self.assertTrue(equal) + def test_expand_on_state_fn(self): """ Tests num_qubits on the original instance and expanded instance of StateFn """ num_qubits = 3 From 8f838359cc4f1dd01c8af544bcaf238c30a76a6a Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 3 Aug 2020 14:00:38 +0200 Subject: [PATCH 09/91] fix linting --- .../aqua/operators/primitive_ops/matrix_op.py | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index f87d6aaf32..1dee01a2f3 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -17,10 +17,10 @@ from typing import Union, Optional, Set, List import logging import numpy as np -from qiskit import QuantumCircuit from scipy.sparse import spmatrix from sympy.combinatorics import Permutation +from qiskit import QuantumCircuit from qiskit.quantum_info import Operator from qiskit.circuit import ParameterExpression, Instruction from qiskit.extensions.hamiltonian_gate import HamiltonianGate @@ -127,14 +127,25 @@ def compose(self, other: OperatorBase) -> OperatorBase: return ComposedOp([self, other]) - def permute(self, indices: List[int] = None): + def permute(self, indices: List[int] = None) -> 'MatrixOp': + """ Creates a new MatrixOp that acts on the permuted qubits. + + Args: + indices: A list defining where each qubit should be permuted. The qubit at index + j should be permuted to position indices[j]. + + Returns: + A new MatrixOp acting on the permuted qubits. + Raises: + AquaError: if indices does not define a new index for each qubit. + """ new_self = self new_matrix_size = max(indices) + 1 # extend the indices to match the size of the new matrix indices = list(filter(lambda x: x not in indices, range(new_matrix_size))) + indices - if self.num_qubits > len(indices): + if self.num_qubits != len(indices): raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < new_matrix_size: # pad the operator with identities @@ -143,8 +154,8 @@ def permute(self, indices: List[int] = None): # decompose permutation into sequence of transpositions transpositions = Permutation(indices).transpositions() - for t in transpositions: - qc.swap(t[0], t[1]) + for trans in transpositions: + qc.swap(trans[0], trans[1]) matrix = CircuitOp(qc).to_matrix() return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # permuted MatrixOp From 655f20944ca498c4c5ad8650d7edd772627bcb7f Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 3 Aug 2020 17:05:55 +0200 Subject: [PATCH 10/91] identity renamed to identity_operator in OperatorBase --- qiskit/aqua/operators/evolutions/evolved_op.py | 2 +- qiskit/aqua/operators/list_ops/list_op.py | 2 +- qiskit/aqua/operators/operator_base.py | 4 ++-- qiskit/aqua/operators/primitive_ops/circuit_op.py | 2 +- qiskit/aqua/operators/primitive_ops/matrix_op.py | 8 ++++---- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- qiskit/aqua/operators/primitive_ops/primitive_op.py | 2 +- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 2 +- qiskit/aqua/operators/state_fns/dict_state_fn.py | 2 +- qiskit/aqua/operators/state_fns/operator_state_fn.py | 4 ++-- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- qiskit/aqua/operators/state_fns/vector_state_fn.py | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index eebe95d8a3..069ec76282 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -89,7 +89,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def identity(self, num_qubits: int) -> 'PrimitiveOp': + def identity_operator(self, num_qubits: int) -> 'PrimitiveOp': from qiskit.quantum_info import Pauli primitive = Pauli(label='I' * num_qubits) return PauliOp(primitive) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index e2c7413d55..512ddec684 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -175,7 +175,7 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat coeff=self.coeff * scalar, abelian=self.abelian) - def identity(self, num_qubits: int) -> OperatorBase: + def identity_operator(self, num_qubits: int) -> OperatorBase: """Returns the PauliOp, with Pauli I as primitive.. Choice of Pauli as identity is arbitrary and could be substituted for other PrimitiveOp.identity. diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 9274d2e2fe..e2207d4444 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -371,7 +371,7 @@ def __rxor__(self, other: Union['OperatorBase', int]) -> 'OperatorBase': return cast(OperatorBase, other).tensor(self) @abstractmethod - def identity(self, num_qubits: int) -> 'OperatorBase': + def identity_operator(self, num_qubits: int) -> 'OperatorBase': """ Returns: identity operator of dimension 'dim'. @@ -445,7 +445,7 @@ def expand(self, num_qubits: int) -> 'OperatorBase': Operator corresponding to self.tensor(identity_operator), where dimension of identity operator is 2 ^ num_qubits. """ - return self.tensor(self.identity(num_qubits)) + return self.tensor(self.identity_operator(num_qubits)) def bind_parameters(self, param_dict: Dict[ParameterExpression, diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 4c53f9af68..a352accb39 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -228,7 +228,7 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] # type: ignore return self - def identity(self, num_qubits: int) -> 'CircuitOp': + def identity_operator(self, num_qubits: int) -> 'CircuitOp': new_qc = QuantumCircuit(num_qubits) for i in range(num_qubits): new_qc.i(i) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 1dee01a2f3..a47b8f677e 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -142,9 +142,6 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': new_self = self new_matrix_size = max(indices) + 1 - # extend the indices to match the size of the new matrix - indices = list(filter(lambda x: x not in indices, range(new_matrix_size))) + indices - if self.num_qubits != len(indices): raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < new_matrix_size: @@ -152,6 +149,9 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': new_self = self.expand(new_matrix_size - self.num_qubits) qc = QuantumCircuit(new_matrix_size) + # extend the indices to match the size of the new matrix + indices = list(filter(lambda x: x not in indices, range(new_matrix_size))) + indices + # decompose permutation into sequence of transpositions transpositions = Permutation(indices).transpositions() for trans in transpositions: @@ -159,7 +159,7 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': matrix = CircuitOp(qc).to_matrix() return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # permuted MatrixOp - def identity(self, num_qubits: int) -> 'MatrixOp': + def identity_operator(self, num_qubits: int) -> 'MatrixOp': identity = np.identity(2**num_qubits, dtype=complex) return MatrixOp(Operator(identity)) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 0da3ca0836..cf08206afa 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -119,7 +119,7 @@ def permute(self, indices: List[int] = None) -> 'PauliOp': new_pauli_list[-index - 1] = pauli_string[-i - 1] return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) - def identity(self, num_qubits: int) -> 'PauliOp': + def identity_operator(self, num_qubits: int) -> 'PauliOp': primitive = Pauli(label='I'*num_qubits) return PauliOp(primitive) diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 4c417c187f..e2aa7af187 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -155,7 +155,7 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp - def identity(self, num_qubits: int) -> 'PrimitiveOp': + def identity_operator(self, num_qubits: int) -> 'PrimitiveOp': raise NotImplementedError def compose(self, other: OperatorBase) -> OperatorBase: diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 67e62dd1e3..18bb4be14f 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -170,7 +170,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: from qiskit.aqua.operators import ComposedOp return ComposedOp([new_self, other]) - def identity(self, num_qubits: int) -> 'CircuitStateFn': + def identity_operator(self, num_qubits: int) -> 'CircuitStateFn': new_qc = QuantumCircuit(num_qubits) for i in range(num_qubits): new_qc.i(i) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index c30599ca19..113a17ce7c 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -109,7 +109,7 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def identity(self, num_qubits: int) -> 'DictStateFn': + def identity_operator(self, num_qubits: int) -> 'DictStateFn': return DictStateFn('0' * num_qubits, is_measurement=self.is_measurement) def tensor(self, other: OperatorBase) -> OperatorBase: diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index 6d82e08db4..b9d33fb93c 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -82,8 +82,8 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def identity(self, num_qubits: int) -> 'OperatorStateFn': - return OperatorStateFn(self.primitive.identity(num_qubits)) + def identity_operator(self, num_qubits: int) -> 'OperatorStateFn': + return OperatorStateFn(self.primitive.identity_operator(num_qubits)) def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, OperatorStateFn): diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 848bf21db8..a34075cca6 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -158,7 +158,7 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat coeff=self.coeff * scalar, is_measurement=self.is_measurement) - def identity(self, num_qubits: int) -> 'StateFn': + def identity_operator(self, num_qubits: int) -> 'StateFn': raise NotImplementedError def tensor(self, other: OperatorBase) -> OperatorBase: diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index a6174b5817..fa01d0d064 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -78,7 +78,7 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def identity(self, num_qubits: int) -> 'VectorStateFn': + def identity_operator(self, num_qubits: int) -> 'VectorStateFn': primitive = np.zeros(2**num_qubits, dtype=complex) return VectorStateFn(primitive) From 5b6f01ea156bc063b5b4870b76aaf41feeee7182 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 3 Aug 2020 17:47:55 +0200 Subject: [PATCH 11/91] OperatorBase.expand renamed to expand_to_dim --- qiskit/aqua/operators/operator_base.py | 2 +- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- qiskit/aqua/operators/primitive_ops/primitive_op.py | 4 ++-- test/aqua/operators/test_op_construction.py | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index e2207d4444..13664c78ae 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -439,7 +439,7 @@ def assign_parameters(self, """ raise NotImplementedError - def expand(self, num_qubits: int) -> 'OperatorBase': + def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': """ Expand the operator with identity operator of dimension corresponding to num_qubits. Returns: Operator corresponding to self.tensor(identity_operator), where dimension of diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index a47b8f677e..828d4e9764 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -146,7 +146,7 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < new_matrix_size: # pad the operator with identities - new_self = self.expand(new_matrix_size - self.num_qubits) + new_self = self.expand_to_dim(new_matrix_size - self.num_qubits) qc = QuantumCircuit(new_matrix_size) # extend the indices to match the size of the new matrix diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index e2aa7af187..b1966c9eff 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -171,9 +171,9 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase) \ # 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(self.num_qubits - other.num_qubits) + other = other.expand_to_dim(self.num_qubits - other.num_qubits) elif other.num_qubits > self.num_qubits: - new_self = self.expand(other.num_qubits - self.num_qubits) # type: ignore + new_self = self.expand_to_dim(other.num_qubits - self.num_qubits) # type: ignore return new_self, other def power(self, exponent: int) -> OperatorBase: diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 5ce5b87959..c478cfb3dc 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -413,12 +413,12 @@ def test_expand_on_state_fn(self): cfn = CircuitStateFn(qc2, is_measurement=True) - cfn_exp = cfn.expand(add_qubits) + cfn_exp = cfn.expand_to_dim(add_qubits) self.assertEqual(cfn_exp.num_qubits, add_qubits + num_qubits) # case OperatorStateFn, with OperatorBase primitive, in our case CircuitStateFn osfn = OperatorStateFn(cfn) - osfn_exp = osfn.expand(add_qubits) + osfn_exp = osfn.expand_to_dim(add_qubits) self.assertEqual(osfn_exp.num_qubits, add_qubits + num_qubits) @@ -426,14 +426,14 @@ def test_expand_on_state_fn(self): dsfn = DictStateFn('1'*num_qubits, is_measurement=True) self.assertEqual(dsfn.num_qubits, num_qubits) - dsfn_exp = dsfn.expand(add_qubits) + dsfn_exp = dsfn.expand_to_dim(add_qubits) self.assertEqual(dsfn_exp.num_qubits, num_qubits + add_qubits) # case VectorStateFn vsfn = VectorStateFn(np.ones(2**num_qubits, dtype=complex)) self.assertEqual(vsfn.num_qubits, num_qubits) - vsfn_exp = vsfn.expand(add_qubits) + vsfn_exp = vsfn.expand_to_dim(add_qubits) self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits) def test_summed_op_equals(self): From 34dddd26d5daca7ff51d4a87d0e15fd77bf73078 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 3 Aug 2020 23:37:18 +0200 Subject: [PATCH 12/91] expand_to_dim overridden for PrimitiveOps --- qiskit/aqua/operators/list_ops/tensored_op.py | 11 +++++++++++ qiskit/aqua/operators/operator_base.py | 6 +++--- qiskit/aqua/operators/primitive_ops/circuit_op.py | 7 ++----- qiskit/aqua/operators/primitive_ops/matrix_op.py | 8 ++++---- qiskit/aqua/operators/primitive_ops/pauli_op.py | 7 +++---- 5 files changed, 23 insertions(+), 16 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 538121b66e..68da236808 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -19,6 +19,7 @@ import numpy as np from qiskit.circuit import ParameterExpression +from qiskit.quantum_info import Pauli from ..operator_base import OperatorBase from .list_op import ListOp @@ -53,6 +54,16 @@ def num_qubits(self) -> int: def distributive(self) -> bool: return False + def expand_to_dim(self, num_qubits: int) -> 'TensoredOp': + """ Appends PauliOp, with Pauli I as primitive, to ``oplist``. + Choice of Pauli as identity is arbitrary and could be substituted for other + PrimitiveOp.identity. + Returns: + identity operator represented by Pauli(label='I'*num_qubit) + """ + from qiskit.aqua.operators import PauliOp + return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))]) + def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, TensoredOp): return TensoredOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 13664c78ae..6c84d3aa56 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -374,7 +374,7 @@ def __rxor__(self, other: Union['OperatorBase', int]) -> 'OperatorBase': def identity_operator(self, num_qubits: int) -> 'OperatorBase': """ Returns: - identity operator of dimension 'dim'. + identity operator of dimension '2**num_qubits'. """ raise NotImplementedError @@ -440,10 +440,10 @@ def assign_parameters(self, raise NotImplementedError def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': - """ Expand the operator with identity operator of dimension corresponding to num_qubits. + """ Expand 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. + identity operator is 2**num_qubits. """ return self.tensor(self.identity_operator(num_qubits)) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index a352accb39..a03b39d794 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -228,11 +228,8 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] # type: ignore return self - def identity_operator(self, num_qubits: int) -> 'CircuitOp': - new_qc = QuantumCircuit(num_qubits) - for i in range(num_qubits): - new_qc.i(i) - return CircuitOp(new_qc) + def expand_to_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""" diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 828d4e9764..7560db7c1e 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -111,6 +111,10 @@ def equals(self, other: OperatorBase) -> bool: return self.coeff == other.coeff and self.primitive == other.primitive return self.coeff * self.primitive == other.coeff * other.primitive # type: ignore + def expand_to_dim(self, num_qubits: int) -> 'MatrixOp': + identity = np.identity(2**num_qubits, dtype=complex) + return MatrixOp(self.primitive.tensor(Operator(identity)), coeff=self.coeff) + def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other.primitive, Operator): # type: ignore return MatrixOp(self.primitive.tensor(other.primitive), # type: ignore @@ -159,10 +163,6 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': matrix = CircuitOp(qc).to_matrix() return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # permuted MatrixOp - def identity_operator(self, num_qubits: int) -> 'MatrixOp': - identity = np.identity(2**num_qubits, dtype=complex) - return MatrixOp(Operator(identity)) - def to_matrix(self, massive: bool = False) -> np.ndarray: return self.primitive.data * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index cf08206afa..8663e64fa1 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -84,6 +84,9 @@ def equals(self, other: OperatorBase) -> bool: return self.primitive == other.primitive + def expand_to_dim(self, num_qubits: int) -> 'PauliOp': + return PauliOp(Pauli(label='I'*num_qubits).kron(self.primitive), coeff=self.coeff) + def tensor(self, other: OperatorBase) -> OperatorBase: # Both Paulis if isinstance(other, PauliOp): @@ -119,10 +122,6 @@ def permute(self, indices: List[int] = None) -> 'PauliOp': new_pauli_list[-index - 1] = pauli_string[-i - 1] return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) - def identity_operator(self, num_qubits: int) -> 'PauliOp': - primitive = Pauli(label='I'*num_qubits) - return PauliOp(primitive) - def compose(self, other: OperatorBase) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other) # type: ignore From 3915c6e4fd6a9a2e1ec7778a934da5e29de7bba2 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 12:00:34 +0200 Subject: [PATCH 13/91] 1) expand_to_dim implemented for each subclass of OperatorBase 2) removed identity_operator --- qiskit/aqua/operators/evolutions/evolved_op.py | 5 ++--- qiskit/aqua/operators/list_ops/composed_op.py | 4 ++++ qiskit/aqua/operators/list_ops/list_op.py | 15 +++------------ qiskit/aqua/operators/list_ops/summed_op.py | 4 ++++ qiskit/aqua/operators/operator_base.py | 11 ++--------- qiskit/aqua/operators/primitive_ops/matrix_op.py | 4 ++-- .../aqua/operators/primitive_ops/primitive_op.py | 6 +++--- .../aqua/operators/state_fns/circuit_state_fn.py | 11 ++++------- qiskit/aqua/operators/state_fns/dict_state_fn.py | 7 +++++-- .../aqua/operators/state_fns/operator_state_fn.py | 6 ++++-- qiskit/aqua/operators/state_fns/state_fn.py | 6 +++--- .../aqua/operators/state_fns/vector_state_fn.py | 6 ++++-- 12 files changed, 40 insertions(+), 45 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 069ec76282..3477a2d59d 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -89,10 +89,9 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def identity_operator(self, num_qubits: int) -> 'PrimitiveOp': + def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': from qiskit.quantum_info import Pauli - primitive = Pauli(label='I' * num_qubits) - return PauliOp(primitive) + return self.tensor(PauliOp(Pauli(label='I'*num_qubits))) def compose(self, other: OperatorBase) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other) # type: ignore diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 170c1ae284..1f080c73d3 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -65,6 +65,10 @@ def distributive(self) -> bool: def adjoint(self) -> OperatorBase: return ComposedOp([op.adjoint() for op in reversed(self.oplist)], coeff=self.coeff) + def expand_to_dim(self, num_qubits: int) -> 'ComposedOp': + return ComposedOp([op.expand_to_dim(num_qubits + self.num_qubits - op.num_qubits) + for op in self.oplist], coeff=self.coeff) + def compose(self, other: OperatorBase) -> OperatorBase: # Try composing with last element in list if isinstance(other, ComposedOp): diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 1ed8dcd202..a1580fd2eb 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -21,7 +21,6 @@ from scipy.sparse import spmatrix from qiskit.circuit import ParameterExpression -from qiskit.quantum_info import Pauli from ..legacy.base_operator import LegacyBaseOperator from ..operator_base import OperatorBase @@ -185,17 +184,6 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat abelian=self.abelian) return self.__class__(self.oplist, coeff=scalar * self.coeff, abelian=self.abelian) - def identity_operator(self, num_qubits: int) -> OperatorBase: - """Returns the PauliOp, with Pauli I as primitive.. - Choice of Pauli as identity is arbitrary and could be substituted - for other PrimitiveOp.identity. - Returns: - identity operator represented by Pauli(label='I'*num_qubit) - """ - from qiskit.aqua.operators import PauliOp - primitive = Pauli(label='I' * num_qubits) - return PauliOp(primitive) - def tensor(self, other: OperatorBase) -> OperatorBase: # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel @@ -214,6 +202,9 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: from .tensored_op import TensoredOp return TensoredOp([self] * other) + def expand_to_dim(self, num_qubits: int) -> 'ListOp': + raise NotImplementedError + def compose(self, other: OperatorBase) -> OperatorBase: # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 9f585da8c1..8e2b4f7b8c 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -56,6 +56,10 @@ def num_qubits(self) -> int: def distributive(self) -> bool: return True + def expand_to_dim(self, num_qubits: int) -> 'SummedOp': + return SummedOp([op.expand_to_dim(num_qubits + self.num_qubits - op.num_qubits) + for op in self.oplist], coeff=self.coeff) + def add(self, other: OperatorBase) -> OperatorBase: """Return Operator addition of ``self`` and ``other``, overloaded by ``+``. diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 8ea506dd87..5562a61ddf 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -381,14 +381,6 @@ def __rxor__(self, other: Union['OperatorBase', int]) -> 'OperatorBase': else: return cast(OperatorBase, other).tensor(self) - @abstractmethod - def identity_operator(self, num_qubits: int) -> 'OperatorBase': - """ - Returns: - identity operator of dimension '2**num_qubits'. - """ - raise NotImplementedError - @abstractmethod def tensor(self, other: 'OperatorBase') -> 'OperatorBase': r""" Return tensor product between self and other, overloaded by ``^``. @@ -450,13 +442,14 @@ def assign_parameters(self, """ raise NotImplementedError + @abstractmethod def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': """ Expand 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. """ - return self.tensor(self.identity_operator(num_qubits)) + raise NotImplementedError def bind_parameters(self, param_dict: Dict[ParameterExpression, diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 7560db7c1e..34aa514b07 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -113,7 +113,7 @@ def equals(self, other: OperatorBase) -> bool: def expand_to_dim(self, num_qubits: int) -> 'MatrixOp': identity = np.identity(2**num_qubits, dtype=complex) - return MatrixOp(self.primitive.tensor(Operator(identity)), coeff=self.coeff) + return MatrixOp(self.primitive.tensor(Operator(identity)), coeff=self.coeff) # type: ignore def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other.primitive, Operator): # type: ignore @@ -161,7 +161,7 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': for trans in transpositions: qc.swap(trans[0], trans[1]) matrix = CircuitOp(qc).to_matrix() - return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # permuted MatrixOp + return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # type: ignore def to_matrix(self, massive: bool = False) -> np.ndarray: return self.primitive.data * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index b1966c9eff..b6cf46b0f3 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -155,9 +155,6 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp - def identity_operator(self, num_qubits: int) -> 'PrimitiveOp': - raise NotImplementedError - def compose(self, other: OperatorBase) -> OperatorBase: raise NotImplementedError @@ -184,6 +181,9 @@ def power(self, exponent: int) -> OperatorBase: temp = temp.compose(self) return temp + def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': + raise NotImplementedError + def exp_i(self) -> OperatorBase: """ Return Operator exponentiation, equaling e^(-i * op)""" # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 18bb4be14f..c0e3309845 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -170,12 +170,6 @@ def compose(self, other: OperatorBase) -> OperatorBase: from qiskit.aqua.operators import ComposedOp return ComposedOp([new_self, other]) - def identity_operator(self, num_qubits: int) -> 'CircuitStateFn': - new_qc = QuantumCircuit(num_qubits) - for i in range(num_qubits): - new_qc.i(i) - return CircuitStateFn(new_qc, is_measurement=self.is_measurement) - def tensor(self, other: OperatorBase) -> OperatorBase: r""" Return tensor product between self and other, overloaded by ``^``. @@ -362,6 +356,9 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] return self + def expand_to_dim(self, num_qubits: int) -> 'CircuitStateFn': + return self.permute(list(range(num_qubits, num_qubits + self.num_qubits))) + def permute(self, permutation: List[int]) -> 'CircuitStateFn': r""" Permute the qubits of the circuit. @@ -373,5 +370,5 @@ def permute(self, permutation: List[int]) -> 'CircuitStateFn': Returns: A new CircuitStateFn 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 CircuitStateFn(new_qc, coeff=self.coeff, is_measurement=self.is_measurement) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 113a17ce7c..a1f1148c9e 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -109,8 +109,11 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def identity_operator(self, num_qubits: int) -> 'DictStateFn': - return DictStateFn('0' * num_qubits, is_measurement=self.is_measurement) + def expand_to_dim(self, num_qubits: int) -> 'DictStateFn': + pad = {'0'*num_qubits: 1} + new_dict = {k1 + k2: v1 * v2 for ((k1, v1,), (k2, v2)) in + itertools.product(self.primitive.items(), pad.items())} + return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def tensor(self, other: OperatorBase) -> OperatorBase: # Both dicts diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index b9d33fb93c..5d9ec25f29 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -82,8 +82,10 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def identity_operator(self, num_qubits: int) -> 'OperatorStateFn': - return OperatorStateFn(self.primitive.identity_operator(num_qubits)) + def expand_to_dim(self, num_qubits: int) -> 'OperatorStateFn': + return OperatorStateFn(self.primitive.expand_to_dim(num_qubits), + coeff=self.coeff, + is_measurement=self.is_measurement) def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, OperatorStateFn): diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index a34075cca6..1a397c0d1d 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -142,6 +142,9 @@ def add(self, other: OperatorBase) -> OperatorBase: def adjoint(self) -> OperatorBase: raise NotImplementedError + def expand_to_dim(self, num_qubits: int) -> 'StateFn': + raise NotImplementedError + def equals(self, other: OperatorBase) -> bool: if not isinstance(other, type(self)) or not self.coeff == other.coeff: return False @@ -158,9 +161,6 @@ def mul(self, scalar: Union[int, float, complex, ParameterExpression]) -> Operat coeff=self.coeff * scalar, is_measurement=self.is_measurement) - def identity_operator(self, num_qubits: int) -> 'StateFn': - raise NotImplementedError - def tensor(self, other: OperatorBase) -> OperatorBase: r""" Return tensor product between self and other, overloaded by ``^``. diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index fa01d0d064..3ccad07e44 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -78,9 +78,11 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def identity_operator(self, num_qubits: int) -> 'VectorStateFn': + def expand_to_dim(self, num_qubits: int) -> 'VectorStateFn': primitive = np.zeros(2**num_qubits, dtype=complex) - return VectorStateFn(primitive) + return VectorStateFn(self.primitive.tensor(primitive), + coeff=self.coeff, + is_measurement=self.is_measurement) def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, VectorStateFn): From 47a48e69647c842b16d0890477da76a1db2f547c Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 14:04:55 +0200 Subject: [PATCH 14/91] fixed linting --- qiskit/aqua/operators/operator_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 5562a61ddf..45318178f2 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -446,8 +446,8 @@ def assign_parameters(self, def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': """ Expand 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. + Operator corresponding to self.tensor(identity_operator), where dimension of identity + operator is 2 ** num_qubits. """ raise NotImplementedError From e197f065f394da8f3e423d1eade132c89022dbe3 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 14:10:38 +0200 Subject: [PATCH 15/91] OperatorStateFn permute implemented --- qiskit/aqua/operators/state_fns/operator_state_fn.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index 5d9ec25f29..213ded155c 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -14,7 +14,7 @@ """ OperatorStateFn Class """ -from typing import Union, Set +from typing import Union, Set, List import numpy as np from qiskit.circuit import ParameterExpression @@ -87,6 +87,11 @@ def expand_to_dim(self, num_qubits: int) -> 'OperatorStateFn': coeff=self.coeff, is_measurement=self.is_measurement) + def permute(self, permutation: List[int]) -> 'OperatorStateFn': + return OperatorStateFn(self.primitive.permute(permutation), + coeff=self.coeff, + is_measurement=self.is_measurement) + def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, OperatorStateFn): return StateFn(self.primitive.tensor(other.primitive), From bcebc5c5a059245a34a2644df6037dd0edee7b86 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 16:07:47 +0200 Subject: [PATCH 16/91] 1) permute for TensoredOp 2) extended documentation --- qiskit/aqua/operators/list_ops/tensored_op.py | 38 +++++++++++++++++++ .../operators/state_fns/operator_state_fn.py | 10 +++++ 2 files changed, 48 insertions(+) diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 68da236808..6959e1f443 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -17,12 +17,15 @@ from typing import List, Union, cast from functools import reduce, partial import numpy as np +from sympy.combinatorics import Permutation +from qiskit import QuantumCircuit from qiskit.circuit import ParameterExpression from qiskit.quantum_info import Pauli from ..operator_base import OperatorBase from .list_op import ListOp +from ... import AquaError class TensoredOp(ListOp): @@ -64,6 +67,41 @@ def expand_to_dim(self, num_qubits: int) -> 'TensoredOp': from qiskit.aqua.operators import PauliOp return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))]) + def permute(self, permutation: List[int]) -> 'ListOp': + r""" + 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 containing the permuted circuit. + Raises: + AquaError: if indices does not define a new index for each qubit. + """ + new_self = self + circuit_size = max(permutation) + 1 + + if self.num_qubits != len(permutation): + raise AquaError("New index must be defined for each qubit of the operator.") + if self.num_qubits < circuit_size: + # pad the operator with identities + new_self = self.expand_to_dim(circuit_size - self.num_qubits) + qc = QuantumCircuit(circuit_size) + # extend the indices to match the size of the circuit + indices = list(filter(lambda x: x not in indices, range(circuit_size))) + permutation + + # decompose permutation into sequence of transpositions + transpositions = Permutation(indices).transpositions() + for trans in transpositions: + qc.swap(trans[0], trans[1]) + + from qiskit.aqua.operators import CircuitOp, MatrixOp + + matrix = CircuitOp(qc).to_matrix() + return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # type: ignore + def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, TensoredOp): return TensoredOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index 213ded155c..04bf2d0bca 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -88,6 +88,16 @@ def expand_to_dim(self, num_qubits: int) -> 'OperatorStateFn': is_measurement=self.is_measurement) def permute(self, permutation: List[int]) -> 'OperatorStateFn': + r""" + 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 OperatorStateFn containing the permuted operator. + """ return OperatorStateFn(self.primitive.permute(permutation), coeff=self.coeff, is_measurement=self.is_measurement) From 07eb035fe158236ec27472bf0d0b48b935b31171 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 16:19:30 +0200 Subject: [PATCH 17/91] 1) TensoredOp.permute moved to ListOp.permute 2) ListOp.permute uses CircuitOps instead of MatrixOps for permutations --- qiskit/aqua/operators/list_ops/list_op.py | 37 ++++++++++++++++++ qiskit/aqua/operators/list_ops/tensored_op.py | 38 ------------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index a1580fd2eb..7574e2f60e 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -19,11 +19,14 @@ import numpy as np from scipy.sparse import spmatrix +from sympy.combinatorics import Permutation +from qiskit import QuantumCircuit from qiskit.circuit import ParameterExpression from ..legacy.base_operator import LegacyBaseOperator from ..operator_base import OperatorBase +from ... import AquaError class ListOp(OperatorBase): @@ -205,6 +208,40 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: def expand_to_dim(self, num_qubits: int) -> 'ListOp': raise NotImplementedError + def permute(self, permutation: List[int]) -> 'ListOp': + r""" + 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 containing the permuted circuit. + Raises: + AquaError: if indices does not define a new index for each qubit. + """ + new_self = self + circuit_size = max(permutation) + 1 + + if self.num_qubits != len(permutation): + raise AquaError("New index must be defined for each qubit of the operator.") + if self.num_qubits < circuit_size: + # pad the operator with identities + new_self = self.expand_to_dim(circuit_size - self.num_qubits) + qc = QuantumCircuit(circuit_size) + # extend the indices to match the size of the circuit + indices = list(filter(lambda x: x not in indices, range(circuit_size))) + permutation + + # decompose permutation into sequence of transpositions + transpositions = Permutation(indices).transpositions() + 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) # type: ignore + def compose(self, other: OperatorBase) -> OperatorBase: # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 6959e1f443..68da236808 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -17,15 +17,12 @@ from typing import List, Union, cast from functools import reduce, partial import numpy as np -from sympy.combinatorics import Permutation -from qiskit import QuantumCircuit from qiskit.circuit import ParameterExpression from qiskit.quantum_info import Pauli from ..operator_base import OperatorBase from .list_op import ListOp -from ... import AquaError class TensoredOp(ListOp): @@ -67,41 +64,6 @@ def expand_to_dim(self, num_qubits: int) -> 'TensoredOp': from qiskit.aqua.operators import PauliOp return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))]) - def permute(self, permutation: List[int]) -> 'ListOp': - r""" - 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 containing the permuted circuit. - Raises: - AquaError: if indices does not define a new index for each qubit. - """ - new_self = self - circuit_size = max(permutation) + 1 - - if self.num_qubits != len(permutation): - raise AquaError("New index must be defined for each qubit of the operator.") - if self.num_qubits < circuit_size: - # pad the operator with identities - new_self = self.expand_to_dim(circuit_size - self.num_qubits) - qc = QuantumCircuit(circuit_size) - # extend the indices to match the size of the circuit - indices = list(filter(lambda x: x not in indices, range(circuit_size))) + permutation - - # decompose permutation into sequence of transpositions - transpositions = Permutation(indices).transpositions() - for trans in transpositions: - qc.swap(trans[0], trans[1]) - - from qiskit.aqua.operators import CircuitOp, MatrixOp - - matrix = CircuitOp(qc).to_matrix() - return MatrixOp(matrix.transpose()) @ new_self @ MatrixOp(matrix) # type: ignore - def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, TensoredOp): return TensoredOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff) From b0062141e078c4a15147f51bd201b41c501b4a8d Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 17:48:59 +0200 Subject: [PATCH 18/91] unexpected indentation fixed. --- qiskit/aqua/operators/operator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 45318178f2..f45cb48f3b 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -444,7 +444,7 @@ def assign_parameters(self, @abstractmethod def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': - """ Expand the operator with identity operator of dimension 2**num_qubits. + r""" 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. From a93d26a800350abbb1b3875dbdf118fc92baf63d Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 18:48:29 +0200 Subject: [PATCH 19/91] permute defined abstract in OperatorBase --- qiskit/aqua/operators/evolutions/evolved_op.py | 3 +++ qiskit/aqua/operators/operator_base.py | 16 ++++++++++++++++ qiskit/aqua/operators/primitive_ops/matrix_op.py | 15 ++++++++------- qiskit/aqua/operators/primitive_ops/pauli_op.py | 12 ++++++------ .../aqua/operators/primitive_ops/primitive_op.py | 3 +++ qiskit/aqua/operators/state_fns/dict_state_fn.py | 5 ++++- qiskit/aqua/operators/state_fns/state_fn.py | 5 ++++- .../aqua/operators/state_fns/vector_state_fn.py | 5 ++++- test/aqua/operators/test_op_construction.py | 4 ++++ 9 files changed, 52 insertions(+), 16 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 3477a2d59d..f6379d6f46 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -93,6 +93,9 @@ def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': from qiskit.quantum_info import Pauli return self.tensor(PauliOp(Pauli(label='I'*num_qubits))) + def permute(self, permutation: List[int]) -> 'OperatorBase': + return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore + def compose(self, other: OperatorBase) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other) # type: ignore diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index f45cb48f3b..0cde00c413 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -451,6 +451,22 @@ def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': """ raise NotImplementedError + @abstractmethod + def permute(self, permutation: List[int]) -> 'OperatorBase': + r""" + 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 circuit. + Raises: + AquaError: if indices does not define a new index for each qubit. + """ + raise NotImplementedError + def bind_parameters(self, param_dict: Dict[ParameterExpression, Union[Number, diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 34aa514b07..7e46b587d5 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -131,12 +131,12 @@ def compose(self, other: OperatorBase) -> OperatorBase: return ComposedOp([self, other]) - def permute(self, indices: List[int] = None) -> 'MatrixOp': + def permute(self, permutation: List[int] = None) -> 'MatrixOp': """ Creates a new MatrixOp that acts on the permuted qubits. Args: - indices: A list defining where each qubit should be permuted. The qubit at index - j should be permuted to position indices[j]. + 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 MatrixOp acting on the permuted qubits. @@ -144,9 +144,9 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': AquaError: if indices does not define a new index for each qubit. """ new_self = self - new_matrix_size = max(indices) + 1 + new_matrix_size = max(permutation) + 1 - if self.num_qubits != len(indices): + if self.num_qubits != len(permutation): raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < new_matrix_size: # pad the operator with identities @@ -154,10 +154,11 @@ def permute(self, indices: List[int] = None) -> 'MatrixOp': qc = QuantumCircuit(new_matrix_size) # extend the indices to match the size of the new matrix - indices = list(filter(lambda x: x not in indices, range(new_matrix_size))) + indices + permutation = list(filter(lambda x: x not in permutation, range(new_matrix_size))) \ + + permutation # decompose permutation into sequence of transpositions - transpositions = Permutation(indices).transpositions() + transpositions = Permutation(permutation).transpositions() for trans in transpositions: qc.swap(trans[0], trans[1]) matrix = CircuitOp(qc).to_matrix() diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 8663e64fa1..088b6f7bd7 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -102,11 +102,11 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def permute(self, indices: List[int] = None) -> 'PauliOp': + def permute(self, permutation: List[int] = None) -> 'PauliOp': """ Permutes the underlying Pauli matrices. Args: - indices: A list defining where each Pauli should be permuted. The Pauli at index - j of the primitive should be permuted to position indices[j]. + permutation: A list defining where each Pauli should be permuted. The Pauli at index + j of the primitive should be permuted to position permutation[j]. Returns: A new PauliOp with the permuted Paulis. For operator (X ^ Y ^ Z) and indices=[1,2,4], it returns (X ^ I ^ Y ^ Z ^ I). @@ -114,11 +114,11 @@ def permute(self, indices: List[int] = None) -> 'PauliOp': AquaError: if number of indices to not match the num_qubits """ pauli_string = self.primitive.__str__() - length = max(indices) + 1 # size of list must be +1 larger then its max index + length = max(permutation) + 1 # size of list must be +1 larger then its max index new_pauli_list = ['I'] * length - if len(indices) != self.num_qubits: + if len(permutation) != self.num_qubits: raise AquaError("List of indices to permute must have the same size as Pauli Operator") - for i, index in enumerate(indices): + for i, index in enumerate(permutation): new_pauli_list[-index - 1] = pauli_string[-i - 1] return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index b6cf46b0f3..f747835357 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -184,6 +184,9 @@ def power(self, exponent: int) -> OperatorBase: def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': raise NotImplementedError + def permute(self, permutation: List[int]) -> 'OperatorBase': + raise NotImplementedError + def exp_i(self) -> OperatorBase: """ Return Operator exponentiation, equaling e^(-i * op)""" # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index a1f1148c9e..74f6abffa0 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -14,7 +14,7 @@ """ DictStateFn Class """ -from typing import Union, Set, cast +from typing import Union, Set, cast, List import itertools import numpy as np from scipy import sparse @@ -109,6 +109,9 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) + def permute(self, permutation: List[int]) -> 'OperatorBase': + raise NotImplementedError + def expand_to_dim(self, num_qubits: int) -> 'DictStateFn': pad = {'0'*num_qubits: 1} new_dict = {k1 + k2: v1 * v2 for ((k1, v1,), (k2, v2)) in diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 1a397c0d1d..bddf5b89d6 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -14,7 +14,7 @@ """ StateFn Class """ -from typing import Union, Optional, Callable, Set, Dict, Tuple +from typing import Union, Optional, Callable, Set, Dict, Tuple, List import numpy as np from qiskit.quantum_info import Statevector @@ -145,6 +145,9 @@ def adjoint(self) -> OperatorBase: def expand_to_dim(self, num_qubits: int) -> 'StateFn': raise NotImplementedError + def permute(self, permutation: List[int]) -> 'OperatorBase': + raise NotImplementedError + def equals(self, other: OperatorBase) -> bool: if not isinstance(other, type(self)) or not self.coeff == other.coeff: return False diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 3ccad07e44..e635d54fd7 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -15,7 +15,7 @@ """ VectorStateFn Class """ -from typing import Union, Set +from typing import Union, Set, List import numpy as np from qiskit.quantum_info import Statevector @@ -78,6 +78,9 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) + def permute(self, permutation: List[int]) -> 'OperatorBase': + raise NotImplementedError + def expand_to_dim(self, num_qubits: int) -> 'VectorStateFn': primitive = np.zeros(2**num_qubits, dtype=complex) return VectorStateFn(self.primitive.tensor(primitive), diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 36fe1d6bd8..b0dd3b3d18 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -402,6 +402,10 @@ def test_permute_on_primitive_op(self): equal = np.allclose(permuted_matrix_op.to_matrix(), expected_matrix_op.to_matrix()) self.assertTrue(equal) + def test_permute_on_list_op(self): + """ Test if permute method of ListOp works correctly and is consistent with other + permute methods. """ + def test_expand_on_state_fn(self): """ Tests num_qubits on the original instance and expanded instance of StateFn """ num_qubits = 3 From b11e47875429390fd1bc6532502bc5d55dfb35b6 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 20:41:45 +0200 Subject: [PATCH 20/91] composition of PrimitiveOp with ComposedOp prepends the ComposedOp.oplist with PrimitiveOp --- qiskit/aqua/operators/primitive_ops/circuit_op.py | 3 +++ qiskit/aqua/operators/primitive_ops/matrix_op.py | 3 +++ qiskit/aqua/operators/primitive_ops/pauli_op.py | 3 +++ 3 files changed, 9 insertions(+) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index a03b39d794..45a15335f7 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -133,6 +133,9 @@ def compose(self, other: OperatorBase) -> OperatorBase: else: return CircuitOp(new_qc, coeff=self.coeff * other.coeff) + if isinstance(other, ComposedOp): + return ComposedOp([self] + other.oplist) + return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 7e46b587d5..1aa5220262 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -129,6 +129,9 @@ def compose(self, other: OperatorBase) -> OperatorBase: return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore coeff=self.coeff * other.coeff) + if isinstance(other, ComposedOp): + return ComposedOp([self] + other.oplist) + return ComposedOp([self, other]) def permute(self, permutation: List[int] = None) -> 'MatrixOp': diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 088b6f7bd7..5d7fcb9b78 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -140,6 +140,9 @@ def compose(self, other: OperatorBase) -> OperatorBase: if isinstance(other, (CircuitOp, CircuitStateFn)): return self.to_circuit_op().compose(other) + if isinstance(other, ComposedOp): + return ComposedOp([self] + other.oplist) + return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: From c98ef818f74c00cc44221fffd25baff3da372c3d Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 21:05:15 +0200 Subject: [PATCH 21/91] Revert "composition of PrimitiveOp with ComposedOp prepends the ComposedOp.oplist with PrimitiveOp" This reverts commit b11e47875429390fd1bc6532502bc5d55dfb35b6. --- qiskit/aqua/operators/primitive_ops/circuit_op.py | 3 --- qiskit/aqua/operators/primitive_ops/matrix_op.py | 3 --- qiskit/aqua/operators/primitive_ops/pauli_op.py | 3 --- 3 files changed, 9 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 45a15335f7..a03b39d794 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -133,9 +133,6 @@ def compose(self, other: OperatorBase) -> OperatorBase: else: return CircuitOp(new_qc, coeff=self.coeff * other.coeff) - if isinstance(other, ComposedOp): - return ComposedOp([self] + other.oplist) - return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 1aa5220262..7e46b587d5 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -129,9 +129,6 @@ def compose(self, other: OperatorBase) -> OperatorBase: return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore coeff=self.coeff * other.coeff) - if isinstance(other, ComposedOp): - return ComposedOp([self] + other.oplist) - return ComposedOp([self, other]) def permute(self, permutation: List[int] = None) -> 'MatrixOp': diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 5d7fcb9b78..088b6f7bd7 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -140,9 +140,6 @@ def compose(self, other: OperatorBase) -> OperatorBase: if isinstance(other, (CircuitOp, CircuitStateFn)): return self.to_circuit_op().compose(other) - if isinstance(other, ComposedOp): - return ComposedOp([self] + other.oplist) - return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: From 253d70796b7d533e9449ac30836ffaab17dfa1bf Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 21:19:48 +0200 Subject: [PATCH 22/91] fixed syntax in ListOp.permute --- qiskit/aqua/operators/list_ops/list_op.py | 5 +++-- test/aqua/operators/test_op_construction.py | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 7574e2f60e..4db64af18f 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -231,10 +231,11 @@ def permute(self, permutation: List[int]) -> 'ListOp': new_self = self.expand_to_dim(circuit_size - self.num_qubits) qc = QuantumCircuit(circuit_size) # extend the indices to match the size of the circuit - indices = list(filter(lambda x: x not in indices, range(circuit_size))) + permutation + permutation = list(filter(lambda x: x not in permutation, range(circuit_size))) \ + + permutation # decompose permutation into sequence of transpositions - transpositions = Permutation(indices).transpositions() + transpositions = Permutation(permutation).transpositions() for trans in transpositions: qc.swap(trans[0], trans[1]) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index b0dd3b3d18..9a88fc3cfa 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -27,8 +27,8 @@ from qiskit.circuit.library import CZGate, ZGate from qiskit.aqua.operators import ( - X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp, MatrixOp, ListOp, - CircuitStateFn, VectorStateFn, DictStateFn, OperatorStateFn + X, Y, Z, I, CX, T, H, Minus, PrimitiveOp, PauliOp, CircuitOp, MatrixOp, CircuitStateFn, + VectorStateFn, DictStateFn, OperatorStateFn, ListOp, ComposedOp, TensoredOp, SummedOp ) @@ -406,6 +406,9 @@ def test_permute_on_list_op(self): """ Test if permute method of ListOp works correctly and is consistent with other permute methods. """ + composed_op = ComposedOp([(X ^ Y ^ Z), (Z ^ X ^ Y).to_circuit_op()]) + composed_op_perm = composed_op.permute([1, 2, 0]) + def test_expand_on_state_fn(self): """ Tests num_qubits on the original instance and expanded instance of StateFn """ num_qubits = 3 From 3d735b952818eb4b05ff856218cd0f9f14d23a24 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 22:02:49 +0200 Subject: [PATCH 23/91] 1) compose in MatrixOp, PauliOp and CircuitOp enhanced, to be consistent with ComposedOp.compose 2) test_compose_consistency added to verify the consistency --- .../operators/primitive_ops/circuit_op.py | 7 ++++ .../aqua/operators/primitive_ops/matrix_op.py | 7 ++++ .../aqua/operators/primitive_ops/pauli_op.py | 7 ++++ test/aqua/operators/test_op_construction.py | 33 ++++++++++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 46ed322fe5..cb7bf13db5 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -133,6 +133,13 @@ def compose(self, other: OperatorBase) -> OperatorBase: else: return CircuitOp(new_qc, coeff=self.coeff * other.coeff) + if isinstance(other, ComposedOp): + comp_with_first = self.compose(other.oplist[0]) + if not isinstance(comp_with_first, ComposedOp): + new_oplist = [comp_with_first] + other.oplist[1:] + return ComposedOp(new_oplist, coeff=other.coeff) + return ComposedOp([self] + other.oplist, coeff=other.coeff) + return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index a69a5c1c07..ac67e0b6af 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -122,6 +122,13 @@ def compose(self, other: OperatorBase) -> OperatorBase: return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore coeff=self.coeff * other.coeff) + if isinstance(other, ComposedOp): + comp_with_first = self.compose(other.oplist[0]) + if not isinstance(comp_with_first, ComposedOp): + new_oplist = [comp_with_first] + other.oplist[1:] + return ComposedOp(new_oplist, coeff=other.coeff) + return ComposedOp([self] + other.oplist, coeff=other.coeff) + return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 1cbcb22b6f..0552386ba8 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -116,6 +116,13 @@ def compose(self, other: OperatorBase) -> OperatorBase: if isinstance(other, (CircuitOp, CircuitStateFn)): return self.to_circuit_op().compose(other) + if isinstance(other, ComposedOp): + comp_with_first = self.compose(other.oplist[0]) + if not isinstance(comp_with_first, ComposedOp): + new_oplist = [comp_with_first] + other.oplist[1:] + return ComposedOp(new_oplist, coeff=other.coeff) + return ComposedOp([self] + other.oplist, coeff=other.coeff) + return ComposedOp([self, other]) def to_matrix(self, massive: bool = False) -> np.ndarray: diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 9d407666fd..a930e4a04b 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -27,7 +27,8 @@ from qiskit.circuit.library import CZGate, ZGate from qiskit.aqua.operators import ( - X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp, MatrixOp, ListOp + X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp, MatrixOp, ListOp, + ComposedOp ) @@ -344,6 +345,36 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'ZZ']) self.assertListEqual([op.coeff for op in sum_op], [10, 2, 3]) + def test_compose_consistency(self): + """Checks if PrimitiveOp @ ComposedOp is consistent with ComposedOp @ PrimitiveOp.""" + + # PauliOp + op1 = (X ^ Y ^ Z) + op2 = (X ^ Y ^ Z) + op3 = (X ^ Y ^ Z).to_circuit_op() + + comp1 = op1 @ ComposedOp([op2, op3]) + comp2 = ComposedOp([op3, op2]) @ op1 + self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist))) + + # CircitOp + op1 = op1.to_circuit_op() + op2 = op2.to_circuit_op() + op3 = op3.to_matrix_op() + + comp1 = op1 @ ComposedOp([op2, op3]) + comp2 = ComposedOp([op3, op2]) @ op1 + self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist))) + + # MatrixOp + op1 = op1.to_matrix_op() + op2 = op2.to_matrix_op() + op3 = op3.to_pauli_op() + + comp1 = op1 @ ComposedOp([op2, op3]) + comp2 = ComposedOp([op3, op2]) @ op1 + self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist))) + def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" with self.subTest('multiplicative factor'): From a83f6ef813be541257fad71d3da71b0fbe80100f Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 4 Aug 2020 23:05:41 +0200 Subject: [PATCH 24/91] DRY applied --- qiskit/aqua/operators/primitive_ops/circuit_op.py | 10 +--------- qiskit/aqua/operators/primitive_ops/matrix_op.py | 10 +--------- qiskit/aqua/operators/primitive_ops/pauli_op.py | 10 +--------- qiskit/aqua/operators/primitive_ops/primitive_op.py | 10 +++++++++- 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index cb7bf13db5..8884600545 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -24,7 +24,6 @@ from ..operator_base import OperatorBase from ..list_ops.summed_op import SummedOp -from ..list_ops.composed_op import ComposedOp from ..list_ops.tensored_op import TensoredOp from .primitive_op import PrimitiveOp @@ -133,14 +132,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: else: return CircuitOp(new_qc, coeff=self.coeff * other.coeff) - if isinstance(other, ComposedOp): - comp_with_first = self.compose(other.oplist[0]) - if not isinstance(comp_with_first, ComposedOp): - new_oplist = [comp_with_first] + other.oplist[1:] - return ComposedOp(new_oplist, coeff=other.coeff) - return ComposedOp([self] + other.oplist, coeff=other.coeff) - - return ComposedOp([self, other]) + return super(CircuitOp, self).compose(other) def to_matrix(self, massive: bool = False) -> np.ndarray: if self.num_qubits > 16 and not massive: diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index ac67e0b6af..0fd0075d14 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -26,7 +26,6 @@ from ..operator_base import OperatorBase from ..primitive_ops.circuit_op import CircuitOp from ..list_ops.summed_op import SummedOp -from ..list_ops.composed_op import ComposedOp from ..list_ops.tensored_op import TensoredOp from .primitive_op import PrimitiveOp from ..legacy.matrix_operator import MatrixOperator @@ -122,14 +121,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore coeff=self.coeff * other.coeff) - if isinstance(other, ComposedOp): - comp_with_first = self.compose(other.oplist[0]) - if not isinstance(comp_with_first, ComposedOp): - new_oplist = [comp_with_first] + other.oplist[1:] - return ComposedOp(new_oplist, coeff=other.coeff) - return ComposedOp([self] + other.oplist, coeff=other.coeff) - - return ComposedOp([self, other]) + return super(MatrixOp, self).compose(other) def to_matrix(self, massive: bool = False) -> np.ndarray: return self.primitive.data * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 0552386ba8..97d77a58ff 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -27,7 +27,6 @@ from ..operator_base import OperatorBase from .primitive_op import PrimitiveOp from ..list_ops.summed_op import SummedOp -from ..list_ops.composed_op import ComposedOp from ..list_ops.tensored_op import TensoredOp from ..legacy.weighted_pauli_operator import WeightedPauliOperator @@ -116,14 +115,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: if isinstance(other, (CircuitOp, CircuitStateFn)): return self.to_circuit_op().compose(other) - if isinstance(other, ComposedOp): - comp_with_first = self.compose(other.oplist[0]) - if not isinstance(comp_with_first, ComposedOp): - new_oplist = [comp_with_first] + other.oplist[1:] - return ComposedOp(new_oplist, coeff=other.coeff) - return ComposedOp([self] + other.oplist, coeff=other.coeff) - - return ComposedOp([self, other]) + return super(PauliOp, self).compose(other) def to_matrix(self, massive: bool = False) -> np.ndarray: if self.num_qubits > 16 and not massive: diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 08fe9451c2..69a53084d3 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -156,7 +156,15 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def compose(self, other: OperatorBase) -> OperatorBase: - raise NotImplementedError + from ..list_ops.composed_op import ComposedOp + if isinstance(other, ComposedOp): + comp_with_first = self.compose(other.oplist[0]) + if not isinstance(comp_with_first, ComposedOp): + new_oplist = [comp_with_first] + other.oplist[1:] + return ComposedOp(new_oplist, coeff=other.coeff) + return ComposedOp([self] + other.oplist, coeff=other.coeff) # type: ignore + + return ComposedOp([self, other]) def _check_zero_for_composition_and_expand(self, other: OperatorBase) -> OperatorBase: if not self.num_qubits == other.num_qubits: From 33e7e91e9aee8029d177d545dd49097d816fa99c Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 11:25:40 +0200 Subject: [PATCH 25/91] Test if ListOp.permute is consistent with PrimitiveOp permute methods --- test/aqua/operators/test_op_construction.py | 54 +++++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 9b17148796..6f353124c7 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -403,11 +403,57 @@ def test_permute_on_primitive_op(self): self.assertTrue(equal) def test_permute_on_list_op(self): - """ Test if permute method of ListOp works correctly and is consistent with other - permute methods. """ + """ Test if permute method of ListOp is consistent with PrimitiveOp permute methods. """ - composed_op = ComposedOp([(X ^ Y ^ Z), (Z ^ X ^ Y).to_circuit_op()]) - composed_op_perm = composed_op.permute([1, 2, 0]) + op1 = (X ^ Y ^ Z).to_circuit_op() + op2 = (Z ^ X ^ Y) + + # ComposedOp + indices = [1, 2, 0] + primitive_op = op1 @ op2 + primitive_op_perm = primitive_op.permute(indices) # CircuitOp.permute + + composed_op = ComposedOp([op1, op2]) + composed_op_perm = composed_op.permute(indices) + + # reduce the ListOp to PrimitiveOp + to_primitive = composed_op_perm.oplist[0] @ composed_op_perm.oplist[1] + # compare resulting PrimitiveOps + equal = np.allclose(primitive_op_perm.to_matrix(), to_primitive.to_matrix()) + self.assertTrue(equal) + + # TensoredOp + indices = [3, 5, 4, 0, 2, 1] + primitive_op = op1 ^ op2 + primitive_op_perm = primitive_op.permute(indices) + + tensored_op = TensoredOp([op1, op2]) + tensored_op_perm = tensored_op.permute(indices) + + # reduce the ListOp to PrimitiveOp + composed_oplist = tensored_op_perm.oplist + to_primitive = composed_oplist[0] \ + @ (composed_oplist[1].oplist[0] ^ composed_oplist[1].oplist[1]) \ + @ composed_oplist[2] + + # compare resulting PrimitiveOps + equal = np.allclose(primitive_op_perm.to_matrix(), to_primitive.to_matrix()) + self.assertTrue(equal) + + # SummedOp + primitive_op = (X ^ Y ^ Z) + summed_op = SummedOp([primitive_op]) + + indices = [1, 2, 0] + primitive_op_perm = primitive_op.permute(indices) # PauliOp.permute + summed_op_perm = summed_op.permute(indices) + + # reduce the ListOp to PrimitiveOp + to_primitive = summed_op_perm.oplist[0] @ primitive_op @ summed_op_perm.oplist[2] + + # compare resulting PrimitiveOps + equal = np.allclose(primitive_op_perm.to_matrix(), to_primitive.to_matrix()) + self.assertTrue(equal) def test_expand_on_state_fn(self): """ Tests num_qubits on the original instance and expanded instance of StateFn """ From 984e23fccce69111d3ac58d9022c42915449cc4d Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 12:49:34 +0200 Subject: [PATCH 26/91] test for expand_to_dim on ListOps --- test/aqua/operators/test_op_construction.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 6f353124c7..4a3d93da90 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -455,6 +455,25 @@ def test_permute_on_list_op(self): equal = np.allclose(primitive_op_perm.to_matrix(), to_primitive.to_matrix()) self.assertTrue(equal) + def test_expand_on_list_op(self): + """ Tests the expected num_qubits on expanded operator. """ + add_qubits = 3 + + # ComposedOp + composed_op = ComposedOp([(X ^ Y ^ Z), (H ^ T), (Z ^ X ^ Y ^ Z).to_matrix_op()]) + expanded = composed_op.expand_to_dim(add_qubits) + self.assertEqual(composed_op.num_qubits + add_qubits, expanded.num_qubits) + + # TensoredOp + tensored_op = TensoredOp([(X ^ Y), (Z ^ I)]) + expanded = tensored_op.expand_to_dim(add_qubits) + self.assertEqual(tensored_op.num_qubits + add_qubits, expanded.num_qubits) + + # SummedOp + summed_op = SummedOp([(X ^ Y), (Z ^ I ^ Z)]) + expanded = summed_op.expand_to_dim(add_qubits) + self.assertEqual(summed_op.num_qubits + add_qubits, expanded.num_qubits) + def test_expand_on_state_fn(self): """ Tests num_qubits on the original instance and expanded instance of StateFn """ num_qubits = 3 From 6088384f351dc200d5d5d2d94a3684dc36533ce4 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 14:07:58 +0200 Subject: [PATCH 27/91] 1) changed signature of compose to allow permutations on operators 2) permutation on operators included in compose method --- .../aqua/operators/evolutions/evolved_op.py | 8 ++++++- qiskit/aqua/operators/list_ops/composed_op.py | 10 +++++++- qiskit/aqua/operators/list_ops/list_op.py | 9 +++++++- qiskit/aqua/operators/operator_base.py | 23 +++++++++++++++++-- .../operators/primitive_ops/circuit_op.py | 8 ++++++- .../aqua/operators/primitive_ops/matrix_op.py | 8 ++++++- .../aqua/operators/primitive_ops/pauli_op.py | 8 ++++++- .../operators/primitive_ops/primitive_op.py | 21 ++++------------- .../operators/state_fns/circuit_state_fn.py | 9 +++++++- qiskit/aqua/operators/state_fns/state_fn.py | 11 ++++++++- 10 files changed, 88 insertions(+), 27 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index f6379d6f46..7f4fd95e31 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -96,7 +96,13 @@ def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': def permute(self, permutation: List[int]) -> 'OperatorBase': return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) self, other = self._check_zero_for_composition_and_expand(other) # type: ignore if isinstance(other, ComposedOp): diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 1f080c73d3..4f129b151b 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -69,7 +69,15 @@ def expand_to_dim(self, num_qubits: int) -> 'ComposedOp': return ComposedOp([op.expand_to_dim(num_qubits + self.num_qubits - op.num_qubits) for op in self.oplist], coeff=self.coeff) - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) + self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # Try composing with last element in list if isinstance(other, ComposedOp): return ComposedOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 4db64af18f..680550dc3d 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -243,7 +243,14 @@ def permute(self, permutation: List[int]) -> 'ListOp': return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc) # type: ignore - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) + self, other = self._check_zero_for_composition_and_expand(other) # type: ignore # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel from .composed_op import ComposedOp diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 0cde00c413..a0edd835bf 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -14,7 +14,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 @@ -516,6 +516,21 @@ 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 _check_zero_for_composition_and_expand(self, other: 'OperatorBase') \ + -> Tuple['OperatorBase', 'OperatorBase']: + new_self = self + 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_to_dim(self.num_qubits - other.num_qubits) + elif other.num_qubits > self.num_qubits: + new_self = self.expand_to_dim(other.num_qubits - self.num_qubits) # type: ignore + return new_self, other + # Composition def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase': @@ -530,7 +545,9 @@ def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase': return self.compose(other) @abstractmethod - def compose(self, other: 'OperatorBase') -> 'OperatorBase': + def compose(self, other: 'OperatorBase', + permute_self: List[int] = None, + permute_other: List[int] = None) -> 'OperatorBase': r""" Return Operator Composition between self and other (linear algebra-style: A@B(x) = A(B(x))), overloaded by ``@``. @@ -544,6 +561,8 @@ def compose(self, other: 'OperatorBase') -> 'OperatorBase': Args: other: The ``OperatorBase`` with which to compose self. + permute_self: ``List[int]`` which defines permutation on self. + permute_other: ``List[int]`` which defines permutation on other. Returns: An ``OperatorBase`` equivalent to the function composition of self and other. diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 90e96dea47..62b5c85e89 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -109,7 +109,13 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) self, other = self._check_zero_for_composition_and_expand(other) # type: ignore # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index d7efcdca80..ea860045e7 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -121,7 +121,13 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) self, other = self._check_zero_for_composition_and_expand(other) # type: ignore if isinstance(other, MatrixOp): diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 5e9b2da427..94eb94f5e7 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -121,7 +121,13 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': new_pauli_list[-index - 1] = pauli_string[-i - 1] return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) self, other = self._check_zero_for_composition_and_expand(other) # type: ignore # If self is identity, just return other. diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index fa9eb25f4f..481aa630f2 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -14,7 +14,7 @@ """ PrimitiveOp Class """ -from typing import Optional, Union, Set, List, Tuple +from typing import Optional, Union, Set, List import logging import numpy as np from scipy.sparse import spmatrix @@ -155,7 +155,9 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: from ..list_ops.composed_op import ComposedOp if isinstance(other, ComposedOp): comp_with_first = self.compose(other.oplist[0]) @@ -166,21 +168,6 @@ def compose(self, other: OperatorBase) -> OperatorBase: return ComposedOp([self, other]) - def _check_zero_for_composition_and_expand(self, other: OperatorBase) \ - -> Tuple['PrimitiveOp', OperatorBase]: - new_self = self - 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_to_dim(self.num_qubits - other.num_qubits) - elif other.num_qubits > self.num_qubits: - new_self = self.expand_to_dim(other.num_qubits - self.num_qubits) # type: ignore - return new_self, other - def power(self, exponent: int) -> OperatorBase: if not isinstance(exponent, int) or exponent <= 0: raise TypeError('power can only take positive int arguments') diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index c0e3309845..54f586bd26 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -139,11 +139,18 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: if not self.is_measurement: raise ValueError( 'Composition with a Statefunctions in the first operand is not defined.') + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) + new_self, other = self._check_zero_for_composition_and_expand(other) # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index bddf5b89d6..1cbf2ee44f 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -234,13 +234,17 @@ def to_density_matrix(self, massive: bool = False) -> np.ndarray: """ raise NotImplementedError - def compose(self, other: OperatorBase) -> OperatorBase: + def compose(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) -> OperatorBase: r""" Composition (Linear algebra-style: A@B(x) = A(B(x))) is not well defined for states in the binary function model, but is well defined for measurements. Args: other: The Operator to compose with self. + permute_self: ``List[int]`` which defines permutation on self. + permute_other: ``List[int]`` which defines permutation on other. Returns: An Operator equivalent to the function composition of self and other. @@ -253,6 +257,11 @@ def compose(self, other: OperatorBase) -> OperatorBase: raise ValueError( 'Composition with a Statefunction in the first operand is not defined.') + if permute_self is not None: + self = self.permute(permute_self) # type: ignore + if permute_other is not None: + other = other.permute(permute_other) + new_self, other = self._check_zero_for_composition_and_expand(other) # TODO maybe include some reduction here in the subclasses - vector and Op, op and Op, etc. # pylint: disable=import-outside-toplevel From 3e646bd5ac69dbf2bc3845c5a64c07ae3b2f1a2d Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 15:56:23 +0200 Subject: [PATCH 28/91] refactoring --- qiskit/aqua/operators/evolutions/evolved_op.py | 8 +++----- qiskit/aqua/operators/list_ops/composed_op.py | 8 +++----- qiskit/aqua/operators/list_ops/list_op.py | 8 +++----- qiskit/aqua/operators/operator_base.py | 8 +++++++- qiskit/aqua/operators/primitive_ops/circuit_op.py | 9 ++++----- qiskit/aqua/operators/primitive_ops/matrix_op.py | 8 +++----- qiskit/aqua/operators/primitive_ops/pauli_op.py | 8 +++----- .../aqua/operators/state_fns/circuit_state_fn.py | 10 +++------- qiskit/aqua/operators/state_fns/state_fn.py | 14 ++++++++------ 9 files changed, 37 insertions(+), 44 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 7f4fd95e31..8ff6ba0651 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -99,11 +99,9 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # type: ignore + self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) if isinstance(other, ComposedOp): return ComposedOp([self] + other.oplist) # type: ignore diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 4f129b151b..d97868a91c 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -72,11 +72,9 @@ def expand_to_dim(self, num_qubits: int) -> 'ComposedOp': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # type: ignore + self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) # Try composing with last element in list if isinstance(other, ComposedOp): diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 680550dc3d..bacde91c60 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -246,11 +246,9 @@ def permute(self, permutation: List[int]) -> 'ListOp': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # type: ignore + self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel from .composed_op import ComposedOp diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index a0edd835bf..dbdcb713ee 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -516,8 +516,14 @@ 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 _check_zero_for_composition_and_expand(self, other: 'OperatorBase') \ + def _check_zero_for_composition_and_expand(self, other: 'OperatorBase', + permute_self: List[int] = None, + permute_other: List[int] = None) \ -> Tuple['OperatorBase', 'OperatorBase']: + if permute_self is not None: + self = self.permute(permute_self) # pylint: disable=self-cls-assignment + if permute_other is not None: + other = other.permute(permute_other) new_self = self if not self.num_qubits == other.num_qubits: # pylint: disable=cyclic-import,import-outside-toplevel diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 62b5c85e89..bcebd7f034 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -112,11 +112,10 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # type: ignore + self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) + # ignore # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero from ..state_fns import CircuitStateFn diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index ea860045e7..9cdca389b9 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -124,11 +124,9 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # type: ignore + self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) if isinstance(other, MatrixOp): return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 94eb94f5e7..cd86992f42 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -124,11 +124,9 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - self, other = self._check_zero_for_composition_and_expand(other) # type: ignore + # type: ignore + self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) # If self is identity, just return other. if not any(self.primitive.x + self.primitive.z): # type: ignore diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 54f586bd26..47bf1c3a9d 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -145,13 +145,9 @@ def compose(self, other: OperatorBase, if not self.is_measurement: raise ValueError( 'Composition with a Statefunctions in the first operand is not defined.') - - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - - new_self, other = self._check_zero_for_composition_and_expand(other) + # type: ignore + new_self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) # pylint: disable=cyclic-import,import-outside-toplevel from ..primitive_ops.circuit_op import CircuitOp diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 1cbf2ee44f..0d43fe1202 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -196,8 +196,15 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp - def _check_zero_for_composition_and_expand(self, other: OperatorBase) \ + def _check_zero_for_composition_and_expand(self, other: OperatorBase, + permute_self: List[int] = None, + permute_other: List[int] = None) \ -> Tuple[OperatorBase, OperatorBase]: + if permute_self is not None: + self = self.permute(permute_self) # pylint: disable=self-cls-assignment + if permute_other is not None: + other = other.permute(permute_other) + new_self = self # pylint: disable=import-outside-toplevel if not self.num_qubits == other.num_qubits: @@ -257,11 +264,6 @@ def compose(self, other: OperatorBase, raise ValueError( 'Composition with a Statefunction in the first operand is not defined.') - if permute_self is not None: - self = self.permute(permute_self) # type: ignore - if permute_other is not None: - other = other.permute(permute_other) - new_self, other = self._check_zero_for_composition_and_expand(other) # TODO maybe include some reduction here in the subclasses - vector and Op, op and Op, etc. # pylint: disable=import-outside-toplevel From 8e34851f13a889c39c9cf927cec6da1055314158 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 18:50:21 +0200 Subject: [PATCH 29/91] unit test for compose with indices --- test/aqua/operators/test_op_construction.py | 40 +++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 4a3d93da90..590d57f090 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -27,8 +27,9 @@ from qiskit.circuit.library import CZGate, ZGate from qiskit.aqua.operators import ( - X, Y, Z, I, CX, T, H, Minus, PrimitiveOp, PauliOp, CircuitOp, MatrixOp, CircuitStateFn, - VectorStateFn, DictStateFn, OperatorStateFn, ListOp, ComposedOp, TensoredOp, SummedOp + X, Y, Z, I, CX, T, H, Minus, PrimitiveOp, PauliOp, CircuitOp, MatrixOp, EvolvedOp, + CircuitStateFn, VectorStateFn, DictStateFn, OperatorStateFn, ListOp, ComposedOp, TensoredOp, + SummedOp ) @@ -538,6 +539,41 @@ def test_compose_consistency(self): comp2 = ComposedOp([op3, op2]) @ op1 self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist))) + def test_compose_with_indices(self): + """ Test compose method using permutation feature.""" + + pauli_op = (X ^ Y ^ Z) + circuit_op = (T ^ H) + matrix_op = (X ^ Y ^ H ^ T).to_matrix_op() + evolved_op = EvolvedOp(matrix_op) + + # composition of PrimitiveOps + num_qubits = 4 + primitive_op = pauli_op @ circuit_op @ matrix_op + composed_op = pauli_op @ circuit_op @ evolved_op + self.assertEqual(primitive_op.num_qubits, num_qubits) + self.assertEqual(composed_op.num_qubits, num_qubits) + + # with permutation + num_qubits = 5 + indices = [1, 4] + permuted_primitive_op = pauli_op @ circuit_op.permute(indices) @ matrix_op + composed_primitive_op = pauli_op.compose(circuit_op, permute_other=indices) @ matrix_op + + self.assertTrue(np.allclose(permuted_primitive_op.to_matrix(), + composed_primitive_op.to_matrix())) + self.assertEqual(num_qubits, permuted_primitive_op.num_qubits) + + # ListOp + num_qubits = 6 + tensored_op = TensoredOp([pauli_op, circuit_op]) + summed_op = pauli_op + circuit_op.permute([2, 1]) + composed_op = circuit_op @ evolved_op @ matrix_op + + list_op = summed_op @ tensored_op.compose(composed_op, permute_self=[1, 2, 3, 5, 4]) + self.assertEqual(num_qubits, list_op.num_qubits) + print('hello') + def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" with self.subTest('multiplicative factor'): From c6e3718a2e9dffb736a077caff615b5f14f33ba0 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 19:15:15 +0200 Subject: [PATCH 30/91] refactoring and fixed linting --- qiskit/aqua/operators/evolutions/evolved_op.py | 5 ++--- qiskit/aqua/operators/list_ops/composed_op.py | 9 ++------- qiskit/aqua/operators/list_ops/list_op.py | 9 +++++---- qiskit/aqua/operators/list_ops/summed_op.py | 4 ---- qiskit/aqua/operators/list_ops/tensored_op.py | 2 +- qiskit/aqua/operators/primitive_ops/circuit_op.py | 6 +++--- qiskit/aqua/operators/primitive_ops/matrix_op.py | 5 ++--- qiskit/aqua/operators/primitive_ops/pauli_op.py | 5 ++--- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- test/aqua/operators/test_op_construction.py | 1 - 10 files changed, 18 insertions(+), 30 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 8ff6ba0651..f76cdaf402 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -99,10 +99,9 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - # type: ignore - self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + self, other = self._check_zero_for_composition_and_expand(other, # type: ignore + permute_self, permute_other) if isinstance(other, ComposedOp): return ComposedOp([self] + other.oplist) # type: ignore diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index d97868a91c..41d1e84e97 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -65,17 +65,12 @@ def distributive(self) -> bool: def adjoint(self) -> OperatorBase: return ComposedOp([op.adjoint() for op in reversed(self.oplist)], coeff=self.coeff) - def expand_to_dim(self, num_qubits: int) -> 'ComposedOp': - return ComposedOp([op.expand_to_dim(num_qubits + self.num_qubits - op.num_qubits) - for op in self.oplist], coeff=self.coeff) - def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - # type: ignore - self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + self, other = self._check_zero_for_composition_and_expand(other, # type: ignore + permute_self, permute_other) # Try composing with last element in list if isinstance(other, ComposedOp): return ComposedOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index bacde91c60..82d3c6a0d9 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -206,7 +206,8 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return TensoredOp([self] * other) def expand_to_dim(self, num_qubits: int) -> 'ListOp': - raise NotImplementedError + return ListOp([op.expand_to_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': r""" @@ -246,9 +247,9 @@ def permute(self, permutation: List[int]) -> 'ListOp': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - # type: ignore - self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + + self, other = self._check_zero_for_composition_and_expand(other, # type: ignore + permute_self, permute_other) # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel from .composed_op import ComposedOp diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 8e2b4f7b8c..9f585da8c1 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -56,10 +56,6 @@ def num_qubits(self) -> int: def distributive(self) -> bool: return True - def expand_to_dim(self, num_qubits: int) -> 'SummedOp': - return SummedOp([op.expand_to_dim(num_qubits + self.num_qubits - op.num_qubits) - for op in self.oplist], coeff=self.coeff) - def add(self, other: OperatorBase) -> OperatorBase: """Return Operator addition of ``self`` and ``other``, overloaded by ``+``. diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 68da236808..dc4ef52df3 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -62,7 +62,7 @@ def expand_to_dim(self, num_qubits: int) -> 'TensoredOp': identity operator represented by Pauli(label='I'*num_qubit) """ from qiskit.aqua.operators import PauliOp - return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))]) + return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))], coeff=self.coeff) def tensor(self, other: OperatorBase) -> OperatorBase: if isinstance(other, TensoredOp): diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index bcebd7f034..c615525dc4 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -112,9 +112,9 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - # type: ignore - self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + + self, other = self._check_zero_for_composition_and_expand(other, # type: ignore + permute_self, permute_other) # ignore # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 9cdca389b9..118462f94f 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -124,10 +124,9 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - # type: ignore - self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + self, other = self._check_zero_for_composition_and_expand(other, # type: ignore + permute_self, permute_other) if isinstance(other, MatrixOp): return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index cd86992f42..ddef3bb951 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -124,10 +124,9 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': def compose(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) -> OperatorBase: - # type: ignore - self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + self, other = self._check_zero_for_composition_and_expand(other, # type: ignore + permute_self, permute_other) # If self is identity, just return other. if not any(self.primitive.x + self.primitive.z): # type: ignore return other * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 0d43fe1202..536c611c78 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -201,7 +201,7 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase, permute_other: List[int] = None) \ -> Tuple[OperatorBase, OperatorBase]: if permute_self is not None: - self = self.permute(permute_self) # pylint: disable=self-cls-assignment + self = self.permute(permute_self) # type: ignore # pylint: disable=self-cls-assignment if permute_other is not None: other = other.permute(permute_other) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 590d57f090..7cae29b138 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -572,7 +572,6 @@ def test_compose_with_indices(self): list_op = summed_op @ tensored_op.compose(composed_op, permute_self=[1, 2, 3, 5, 4]) self.assertEqual(num_qubits, list_op.num_qubits) - print('hello') def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" From f757fb82b69ef596717d161c6a49f219a355d2c6 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 20:06:01 +0200 Subject: [PATCH 31/91] 1) StateFn.compose expands the shorter operators with identity 2) refactored _check_zero_for_composition_and_expand 3) unit test for new composition features of StateFns 4) fixing style --- qiskit/aqua/operators/list_ops/list_op.py | 4 +-- .../aqua/operators/primitive_ops/matrix_op.py | 4 +-- qiskit/aqua/operators/state_fns/state_fn.py | 30 +++++++------------ test/aqua/operators/test_op_construction.py | 17 +++++++++-- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 82d3c6a0d9..047890c996 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -232,8 +232,8 @@ def permute(self, permutation: List[int]) -> 'ListOp': new_self = self.expand_to_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 + permutation \ + = list(filter(lambda x: x not in permutation, range(circuit_size))) + permutation # decompose permutation into sequence of transpositions transpositions = Permutation(permutation).transpositions() diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 118462f94f..b1533ea98c 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -156,8 +156,8 @@ def permute(self, permutation: List[int] = None) -> 'MatrixOp': qc = QuantumCircuit(new_matrix_size) # extend the indices to match the size of the new matrix - permutation = list(filter(lambda x: x not in permutation, range(new_matrix_size))) \ - + permutation + permutation \ + = list(filter(lambda x: x not in permutation, range(new_matrix_size))) + permutation # decompose permutation into sequence of transpositions transpositions = Permutation(permutation).transpositions() diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 536c611c78..32add054e3 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -200,27 +200,17 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase, permute_self: List[int] = None, permute_other: List[int] = None) \ -> Tuple[OperatorBase, OperatorBase]: - if permute_self is not None: - self = self.permute(permute_self) # type: ignore # pylint: disable=self-cls-assignment - if permute_other is not None: - other = other.permute(permute_other) - new_self = self - # pylint: disable=import-outside-toplevel - if not self.num_qubits == other.num_qubits: - from qiskit.aqua.operators import Zero - if self == StateFn({'0': 1}, is_measurement=True): - # Zero is special - we'll expand it to the correct qubit number. - new_self = StateFn('0' * self.num_qubits, is_measurement=True) - elif other == Zero: - # Zero is special - we'll expand it to the correct qubit number. - other = StateFn('0' * self.num_qubits) - else: - raise ValueError( - 'Composition is not defined over Operators of different dimensions, {} and {}, ' - 'respectively.'.format(self.num_qubits, other.num_qubits)) - - return new_self, other + from ..operator_globals import Zero + + if self == StateFn({'0': 1}, is_measurement=True): + # Zero is special - we'll expand it to the correct qubit number. + return StateFn('0' * other.num_qubits, is_measurement=True), other + elif other == Zero: + # Zero is special - we'll expand it to the correct qubit number. + return self, StateFn('0' * self.num_qubits) + + return super()._check_zero_for_composition_and_expand(other, permute_self, permute_other) def to_matrix(self, massive: bool = False) -> np.ndarray: raise NotImplementedError diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 7cae29b138..9921f733ef 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -433,9 +433,9 @@ def test_permute_on_list_op(self): # reduce the ListOp to PrimitiveOp composed_oplist = tensored_op_perm.oplist - to_primitive = composed_oplist[0] \ - @ (composed_oplist[1].oplist[0] ^ composed_oplist[1].oplist[1]) \ - @ composed_oplist[2] + to_primitive = \ + composed_oplist[0] @ (composed_oplist[1].oplist[0] ^ composed_oplist[1].oplist[1]) @ \ + composed_oplist[2] # compare resulting PrimitiveOps equal = np.allclose(primitive_op_perm.to_matrix(), to_primitive.to_matrix()) @@ -573,6 +573,17 @@ def test_compose_with_indices(self): list_op = summed_op @ tensored_op.compose(composed_op, permute_self=[1, 2, 3, 5, 4]) self.assertEqual(num_qubits, list_op.num_qubits) + num_qubits = 4 + circuit_fn = CircuitStateFn(primitive=circuit_op.primitive, is_measurement=True) + operator_fn = OperatorStateFn(primitive=circuit_op ^ circuit_op, is_measurement=True) + + no_perm_op = circuit_fn @ operator_fn + self.assertEqual(no_perm_op.num_qubits, num_qubits) + + indices = [0, 4] + perm_op = circuit_fn.compose(operator_fn, permute_self=indices) + self.assertEqual(perm_op.num_qubits, max(indices) + 1) + def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" with self.subTest('multiplicative factor'): From f6ac702dd93964fd5dd4e9efdc093529e26d8c72 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 22:44:28 +0200 Subject: [PATCH 32/91] fixed unexpected indentation --- qiskit/aqua/operators/operator_base.py | 4 ++-- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index dbdcb713ee..ad3108389d 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -445,6 +445,7 @@ def assign_parameters(self, @abstractmethod def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': r""" 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. @@ -453,8 +454,7 @@ def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': @abstractmethod def permute(self, permutation: List[int]) -> 'OperatorBase': - r""" - Permutes the qubits of the operator. + r""" Permutes the qubits of the operator. Args: permutation: A list defining where each qubit should be permuted. The qubit at index diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 32add054e3..d1c7d860b0 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -201,7 +201,7 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase, permute_other: List[int] = None) \ -> Tuple[OperatorBase, OperatorBase]: - from ..operator_globals import Zero + from qiskit.aqua.operators import Zero if self == StateFn({'0': 1}, is_measurement=True): # Zero is special - we'll expand it to the correct qubit number. From 59dd5fc09da7814f29c833d5f41e7a1a73fe492b Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 5 Aug 2020 23:33:29 +0200 Subject: [PATCH 33/91] doc html fix --- qiskit/aqua/operators/list_ops/tensored_op.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index dc4ef52df3..46192c1549 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -55,11 +55,11 @@ def distributive(self) -> bool: return False def expand_to_dim(self, num_qubits: int) -> 'TensoredOp': - """ Appends PauliOp, with Pauli I as primitive, to ``oplist``. - Choice of Pauli as identity is arbitrary and could be substituted for other - PrimitiveOp.identity. + """ Appends PauliOp, with Pauli I as primitive, to ``oplist``. Choice of Pauli as + identity is arbitrary and could be substituted for other PrimitiveOp identity. + Returns: - identity operator represented by Pauli(label='I'*num_qubit) + identity operator represented by Pauli """ from qiskit.aqua.operators import PauliOp return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))], coeff=self.coeff) From f269e5f4d31d052df62f9537a0a18b7cb1d5c516 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 00:05:31 +0200 Subject: [PATCH 34/91] fix unexpected indentation --- qiskit/aqua/operators/primitive_ops/pauli_op.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index ddef3bb951..2cd75b5014 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -103,12 +103,15 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def permute(self, permutation: List[int] = None) -> 'PauliOp': """ Permutes the underlying Pauli matrices. + Args: permutation: A list defining where each Pauli should be permuted. The Pauli at index j of the primitive should be permuted to position permutation[j]. + Returns: A new PauliOp with the permuted Paulis. For operator (X ^ Y ^ Z) and indices=[1,2,4], it returns (X ^ I ^ Y ^ Z ^ I). + Raises: AquaError: if number of indices to not match the num_qubits """ From 691ab948bcbdead182dcf92e9d55537b79c7a739 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 09:42:23 +0200 Subject: [PATCH 35/91] 1) expand_to_dim renamed to expand_with_identities (expand_to_dim was misleading, because its parameter is not the target dimension, but the number or qubits to add to operator) 2) documentation for the new features improved --- .../aqua/operators/evolutions/evolved_op.py | 2 +- qiskit/aqua/operators/list_ops/list_op.py | 11 ++++---- qiskit/aqua/operators/list_ops/tensored_op.py | 8 +++--- qiskit/aqua/operators/operator_base.py | 11 ++++---- .../operators/primitive_ops/circuit_op.py | 2 +- .../aqua/operators/primitive_ops/matrix_op.py | 9 +++--- .../aqua/operators/primitive_ops/pauli_op.py | 10 +++---- .../operators/primitive_ops/primitive_op.py | 2 +- .../operators/state_fns/circuit_state_fn.py | 2 +- .../aqua/operators/state_fns/dict_state_fn.py | 2 +- .../operators/state_fns/operator_state_fn.py | 4 +-- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- .../operators/state_fns/vector_state_fn.py | 2 +- test/aqua/operators/test_op_construction.py | 28 +++++++++---------- 14 files changed, 49 insertions(+), 46 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index f76cdaf402..b8fa9f7357 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -89,7 +89,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': + def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': from qiskit.quantum_info import Pauli return self.tensor(PauliOp(Pauli(label='I'*num_qubits))) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 047890c996..5964225187 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -205,8 +205,8 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: from .tensored_op import TensoredOp return TensoredOp([self] * other) - def expand_to_dim(self, num_qubits: int) -> 'ListOp': - return ListOp([op.expand_to_dim(num_qubits + self.num_qubits - op.num_qubits) + def expand_with_identity(self, num_qubits: int) -> 'ListOp': + return ListOp([op.expand_with_identity(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': @@ -218,9 +218,10 @@ def permute(self, permutation: List[int]) -> 'ListOp': j should be permuted to position permutation[j]. Returns: - A new ListOp containing the permuted circuit. + A new ListOp representing the permuted operator. + Raises: - AquaError: if indices does not define a new index for each qubit. + AquaError: if indices do not define a new index for each qubit. """ new_self = self circuit_size = max(permutation) + 1 @@ -229,7 +230,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < circuit_size: # pad the operator with identities - new_self = self.expand_to_dim(circuit_size - self.num_qubits) + new_self = self.expand_with_identity(circuit_size - self.num_qubits) qc = QuantumCircuit(circuit_size) # extend the indices to match the size of the circuit permutation \ diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 46192c1549..d7702cd8f0 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -54,12 +54,12 @@ def num_qubits(self) -> int: def distributive(self) -> bool: return False - def expand_to_dim(self, num_qubits: int) -> 'TensoredOp': - """ Appends PauliOp, with Pauli I as primitive, to ``oplist``. Choice of Pauli as - identity is arbitrary and could be substituted for other PrimitiveOp identity. + def expand_with_identity(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: - identity operator represented by Pauli + Identity operator represented by PauliOp. """ from qiskit.aqua.operators import PauliOp return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))], coeff=self.coeff) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index ad3108389d..32ac5c17fc 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -443,7 +443,7 @@ def assign_parameters(self, raise NotImplementedError @abstractmethod - def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': + def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': r""" Expands the operator with identity operator of dimension 2**num_qubits. Returns: @@ -461,9 +461,10 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': j should be permuted to position permutation[j]. Returns: - A new OperatorBase containing the permuted circuit. + A new OperatorBase containing the permuted operator. + Raises: - AquaError: if indices does not define a new index for each qubit. + AquaError: if indices do not define a new index for each qubit. """ raise NotImplementedError @@ -532,9 +533,9 @@ def _check_zero_for_composition_and_expand(self, other: 'OperatorBase', # 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_to_dim(self.num_qubits - other.num_qubits) + other = other.expand_with_identity(self.num_qubits - other.num_qubits) elif other.num_qubits > self.num_qubits: - new_self = self.expand_to_dim(other.num_qubits - self.num_qubits) # type: ignore + new_self = self.expand_with_identity(other.num_qubits - self.num_qubits) # type: ignore return new_self, other # Composition diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index c615525dc4..e8b197a6f0 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -232,7 +232,7 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] # type: ignore return self - def expand_to_dim(self, num_qubits: int) -> 'CircuitOp': + def expand_with_identity(self, num_qubits: int) -> 'CircuitOp': return self.permute(list(range(num_qubits, num_qubits + self.num_qubits))) def permute(self, permutation: List[int]) -> 'CircuitOp': diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index b1533ea98c..4609c2b1bd 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -110,7 +110,7 @@ def equals(self, other: OperatorBase) -> bool: return self.coeff == other.coeff and self.primitive == other.primitive return self.coeff * self.primitive == other.coeff * other.primitive # type: ignore - def expand_to_dim(self, num_qubits: int) -> 'MatrixOp': + def expand_with_identity(self, num_qubits: int) -> 'MatrixOp': identity = np.identity(2**num_qubits, dtype=complex) return MatrixOp(self.primitive.tensor(Operator(identity)), coeff=self.coeff) # type: ignore @@ -141,9 +141,10 @@ def permute(self, permutation: List[int] = None) -> 'MatrixOp': j should be permuted to position permutation[j]. Returns: - A new MatrixOp acting on the permuted qubits. + A new MatrixOp representing the permuted operator. + Raises: - AquaError: if indices does not define a new index for each qubit. + AquaError: if indices do not define a new index for each qubit. """ new_self = self new_matrix_size = max(permutation) + 1 @@ -152,7 +153,7 @@ def permute(self, permutation: List[int] = None) -> 'MatrixOp': raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < new_matrix_size: # pad the operator with identities - new_self = self.expand_to_dim(new_matrix_size - self.num_qubits) + new_self = self.expand_with_identity(new_matrix_size - self.num_qubits) qc = QuantumCircuit(new_matrix_size) # extend the indices to match the size of the new matrix diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 2cd75b5014..048a340971 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -83,7 +83,7 @@ def equals(self, other: OperatorBase) -> bool: return self.primitive == other.primitive - def expand_to_dim(self, num_qubits: int) -> 'PauliOp': + def expand_with_identity(self, num_qubits: int) -> 'PauliOp': return PauliOp(Pauli(label='I'*num_qubits).kron(self.primitive), coeff=self.coeff) def tensor(self, other: OperatorBase) -> OperatorBase: @@ -102,18 +102,18 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def permute(self, permutation: List[int] = None) -> 'PauliOp': - """ Permutes the underlying Pauli matrices. + """ Permutes the sequence of Pauli matrices. Args: permutation: A list defining where each Pauli should be permuted. The Pauli at index j of the primitive should be permuted to position permutation[j]. Returns: - A new PauliOp with the permuted Paulis. For operator (X ^ Y ^ Z) and indices=[1,2,4], - it returns (X ^ I ^ Y ^ Z ^ I). + A new PauliOp representing the permuted operator. For operator (X ^ Y ^ Z) and + indices=[1,2,4], it returns (X ^ I ^ Y ^ Z ^ I). Raises: - AquaError: if number of indices to not match the num_qubits + AquaError: if indices do not define a new index for each qubit. """ pauli_string = self.primitive.__str__() length = max(permutation) + 1 # size of list must be +1 larger then its max index diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 481aa630f2..bdcc9bb0fe 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -176,7 +176,7 @@ def power(self, exponent: int) -> OperatorBase: temp = temp.compose(self) return temp - def expand_to_dim(self, num_qubits: int) -> 'OperatorBase': + def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': raise NotImplementedError def permute(self, permutation: List[int]) -> 'OperatorBase': diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 47bf1c3a9d..a20005dace 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -359,7 +359,7 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] return self - def expand_to_dim(self, num_qubits: int) -> 'CircuitStateFn': + def expand_with_identity(self, num_qubits: int) -> 'CircuitStateFn': return self.permute(list(range(num_qubits, num_qubits + self.num_qubits))) def permute(self, permutation: List[int]) -> 'CircuitStateFn': diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 74f6abffa0..de16467777 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -112,7 +112,7 @@ def adjoint(self) -> OperatorBase: def permute(self, permutation: List[int]) -> 'OperatorBase': raise NotImplementedError - def expand_to_dim(self, num_qubits: int) -> 'DictStateFn': + def expand_with_identity(self, num_qubits: int) -> 'DictStateFn': pad = {'0'*num_qubits: 1} new_dict = {k1 + k2: v1 * v2 for ((k1, v1,), (k2, v2)) in itertools.product(self.primitive.items(), pad.items())} diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index 04bf2d0bca..fcf08b3221 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -82,8 +82,8 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def expand_to_dim(self, num_qubits: int) -> 'OperatorStateFn': - return OperatorStateFn(self.primitive.expand_to_dim(num_qubits), + def expand_with_identity(self, num_qubits: int) -> 'OperatorStateFn': + return OperatorStateFn(self.primitive.expand_with_identity(num_qubits), coeff=self.coeff, is_measurement=self.is_measurement) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index d1c7d860b0..30b2a0b6a0 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -142,7 +142,7 @@ def add(self, other: OperatorBase) -> OperatorBase: def adjoint(self) -> OperatorBase: raise NotImplementedError - def expand_to_dim(self, num_qubits: int) -> 'StateFn': + def expand_with_identity(self, num_qubits: int) -> 'StateFn': raise NotImplementedError def permute(self, permutation: List[int]) -> 'OperatorBase': diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index e635d54fd7..97d49a2d5c 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -81,7 +81,7 @@ def adjoint(self) -> OperatorBase: def permute(self, permutation: List[int]) -> 'OperatorBase': raise NotImplementedError - def expand_to_dim(self, num_qubits: int) -> 'VectorStateFn': + def expand_with_identity(self, num_qubits: int) -> 'VectorStateFn': primitive = np.zeros(2**num_qubits, dtype=complex) return VectorStateFn(self.primitive.tensor(primitive), coeff=self.coeff, diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 9921f733ef..46fdd5d90d 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -349,7 +349,7 @@ def test_summed_op_reduce(self): def test_compose_op_of_different_dim(self): """ Test if smaller operator expands to correct dim when composed with bigger operator. - Test if compose methods of PrimitiveOp types are consistent. + Test if PrimitiveOps compose methods are consistent. """ # PauliOps of different dim xy_p = (X ^ Y) @@ -377,7 +377,7 @@ def test_compose_op_of_different_dim(self): self.assertTrue(np.allclose(matrix_op.to_matrix(), circuit_op.to_matrix(), rtol=1e-14)) def test_permute_on_primitive_op(self): - """ Test if permute methods of PrimitiveOps are consistent and work correctly. """ + """ Test if permute methods of PrimitiveOps are consistent and work as expected. """ indices = [1, 2, 4] # PauliOp @@ -404,7 +404,7 @@ def test_permute_on_primitive_op(self): self.assertTrue(equal) def test_permute_on_list_op(self): - """ Test if permute method of ListOp is consistent with PrimitiveOp permute methods. """ + """ Test if ListOp permute method is consistent with PrimitiveOps permute methods. """ op1 = (X ^ Y ^ Z).to_circuit_op() op2 = (Z ^ X ^ Y) @@ -457,26 +457,26 @@ def test_permute_on_list_op(self): self.assertTrue(equal) def test_expand_on_list_op(self): - """ Tests the expected num_qubits on expanded operator. """ + """ Test if expanded ListOp has expected num_qubits. """ add_qubits = 3 # ComposedOp composed_op = ComposedOp([(X ^ Y ^ Z), (H ^ T), (Z ^ X ^ Y ^ Z).to_matrix_op()]) - expanded = composed_op.expand_to_dim(add_qubits) + expanded = composed_op.expand_with_identity(add_qubits) self.assertEqual(composed_op.num_qubits + add_qubits, expanded.num_qubits) # TensoredOp tensored_op = TensoredOp([(X ^ Y), (Z ^ I)]) - expanded = tensored_op.expand_to_dim(add_qubits) + expanded = tensored_op.expand_with_identity(add_qubits) self.assertEqual(tensored_op.num_qubits + add_qubits, expanded.num_qubits) # SummedOp summed_op = SummedOp([(X ^ Y), (Z ^ I ^ Z)]) - expanded = summed_op.expand_to_dim(add_qubits) + expanded = summed_op.expand_with_identity(add_qubits) self.assertEqual(summed_op.num_qubits + add_qubits, expanded.num_qubits) def test_expand_on_state_fn(self): - """ Tests num_qubits on the original instance and expanded instance of StateFn """ + """ Test if expanded StateFn has expected num_qubits. """ num_qubits = 3 add_qubits = 2 @@ -486,12 +486,12 @@ def test_expand_on_state_fn(self): cfn = CircuitStateFn(qc2, is_measurement=True) - cfn_exp = cfn.expand_to_dim(add_qubits) + cfn_exp = cfn.expand_with_identity(add_qubits) self.assertEqual(cfn_exp.num_qubits, add_qubits + num_qubits) # case OperatorStateFn, with OperatorBase primitive, in our case CircuitStateFn osfn = OperatorStateFn(cfn) - osfn_exp = osfn.expand_to_dim(add_qubits) + osfn_exp = osfn.expand_with_identity(add_qubits) self.assertEqual(osfn_exp.num_qubits, add_qubits + num_qubits) @@ -499,18 +499,18 @@ def test_expand_on_state_fn(self): dsfn = DictStateFn('1'*num_qubits, is_measurement=True) self.assertEqual(dsfn.num_qubits, num_qubits) - dsfn_exp = dsfn.expand_to_dim(add_qubits) + dsfn_exp = dsfn.expand_with_identity(add_qubits) self.assertEqual(dsfn_exp.num_qubits, num_qubits + add_qubits) # case VectorStateFn vsfn = VectorStateFn(np.ones(2**num_qubits, dtype=complex)) self.assertEqual(vsfn.num_qubits, num_qubits) - vsfn_exp = vsfn.expand_to_dim(add_qubits) + vsfn_exp = vsfn.expand_with_identity(add_qubits) self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits) def test_compose_consistency(self): - """Checks if PrimitiveOp @ ComposedOp is consistent with ComposedOp @ PrimitiveOp.""" + """Test if PrimitiveOp @ ComposedOp is consistent with ComposedOp @ PrimitiveOp.""" # PauliOp op1 = (X ^ Y ^ Z) @@ -540,7 +540,7 @@ def test_compose_consistency(self): self.assertListEqual(comp1.oplist, list(reversed(comp2.oplist))) def test_compose_with_indices(self): - """ Test compose method using permutation feature.""" + """ Test compose method using its permutation feature.""" pauli_op = (X ^ Y ^ Z) circuit_op = (T ^ H) From aed694019c0d96c2a7b9d197a1380a47fec899f8 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 10:21:48 +0200 Subject: [PATCH 36/91] fixed line too long --- qiskit/aqua/operators/operator_base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 32ac5c17fc..9394a6b01a 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -535,7 +535,8 @@ def _check_zero_for_composition_and_expand(self, other: 'OperatorBase', elif other.num_qubits < self.num_qubits: other = other.expand_with_identity(self.num_qubits - other.num_qubits) elif other.num_qubits > self.num_qubits: - new_self = self.expand_with_identity(other.num_qubits - self.num_qubits) # type: ignore + # type: ignore + new_self = self.expand_with_identity(other.num_qubits - self.num_qubits) return new_self, other # Composition From 1dbff1f37c02f88782f76fe93b85d715571eb559 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 11:42:53 +0200 Subject: [PATCH 37/91] permute implemented for DictStateFn --- .../aqua/operators/state_fns/dict_state_fn.py | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index de16467777..786cbe5011 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -18,10 +18,11 @@ import itertools import numpy as np from scipy import sparse +from sympy.combinatorics import Permutation from qiskit.result import Result from qiskit.circuit import ParameterExpression -from qiskit.aqua import aqua_globals +from qiskit.aqua import aqua_globals, AquaError from ..operator_base import OperatorBase from .state_fn import StateFn @@ -110,12 +111,23 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def permute(self, permutation: List[int]) -> 'OperatorBase': - raise NotImplementedError + new_num_qubits = max(permutation) + 1 + if self.num_qubits != len(permutation): + raise AquaError("New index must be defined for each qubit of the operator.") + + # helper function to permute the key + def perm(key): + list_key = ['0'] * new_num_qubits + for i, k in enumerate(permutation): + list_key[k] = key[i] + return str(list_key) + + new_dict = {perm(key): value for key, value in self.primitive.items()} + return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def expand_with_identity(self, num_qubits: int) -> 'DictStateFn': - pad = {'0'*num_qubits: 1} - new_dict = {k1 + k2: v1 * v2 for ((k1, v1,), (k2, v2)) in - itertools.product(self.primitive.items(), pad.items())} + pad = '0'*num_qubits + new_dict = {key + pad: value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def tensor(self, other: OperatorBase) -> OperatorBase: From c599147641d352ca825bbf851ab5d6c612c6bff0 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 20:02:37 +0200 Subject: [PATCH 38/91] 1) VectorStateFn.to_dict_fn and DictStateFn.to_vector_state_fn implemented 2) VectorStateFn permute implemented 3) unit tests for the new functionality --- .../aqua/operators/state_fns/dict_state_fn.py | 13 ++++++++--- .../operators/state_fns/vector_state_fn.py | 8 ++++++- test/aqua/operators/test_op_construction.py | 23 +++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 786cbe5011..c33a7f3149 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -18,7 +18,6 @@ import itertools import numpy as np from scipy import sparse -from sympy.combinatorics import Permutation from qiskit.result import Result from qiskit.circuit import ParameterExpression @@ -110,7 +109,7 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def permute(self, permutation: List[int]) -> 'OperatorBase': + def permute(self, permutation: List[int]) -> 'DictStateFn': new_num_qubits = max(permutation) + 1 if self.num_qubits != len(permutation): raise AquaError("New index must be defined for each qubit of the operator.") @@ -120,7 +119,7 @@ def perm(key): list_key = ['0'] * new_num_qubits for i, k in enumerate(permutation): list_key[k] = key[i] - return str(list_key) + return ''.join(list_key) new_dict = {perm(key): value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) @@ -130,6 +129,14 @@ def expand_with_identity(self, num_qubits: int) -> 'DictStateFn': new_dict = {key + pad: value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) + def to_vector_state_fn(self) -> 'VectorStateFn': + states = int(2 ** self.num_qubits) + probs = np.zeros(states) + 0.j + for k, v in self.primitive.items(): + probs[int(k, 2)] = v + from qiskit.aqua.operators import VectorStateFn + return VectorStateFn(probs, coeff=self.coeff, is_measurement=self.is_measurement) + def tensor(self, other: OperatorBase) -> OperatorBase: # Both dicts if isinstance(other, DictStateFn): diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 97d49a2d5c..726690092b 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -79,7 +79,13 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def permute(self, permutation: List[int]) -> 'OperatorBase': - raise NotImplementedError + return self.to_dict_fn().permute(permutation).to_vector_state_fn() + + def to_dict_fn(self) -> 'DictStateFn': + num_qubits = self.num_qubits + new_dict = {format(i, 'b').zfill(num_qubits): v for i, v in enumerate(self.primitive.data)} + from qiskit.aqua.operators import DictStateFn + return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def expand_with_identity(self, num_qubits: int) -> 'VectorStateFn': primitive = np.zeros(2**num_qubits, dtype=complex) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 46fdd5d90d..e81eef88bb 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -509,6 +509,29 @@ def test_expand_on_state_fn(self): vsfn_exp = vsfn.expand_with_identity(add_qubits) self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits) + def test_permute_on_state_fn(self): + """ Test if StateFns permute are consistent. """ + + num_qubits = 4 + dim = 2**num_qubits + primitive_list = [1.0/(i+1) for i in range(dim)] + primitive_dict = {format(i, 'b').zfill(num_qubits): 1.0/(i+1) for i in range(dim)} + + dict_fn = DictStateFn(primitive=primitive_dict, is_measurement=True) + vec_fn = VectorStateFn(primitive=primitive_list, is_measurement=True) + + # check if dict_fn and vec_fn are equivalent + equivalent = np.allclose(dict_fn.to_matrix(), vec_fn.to_matrix()) + self.assertTrue(equivalent) + + # permute + indices = [2, 3, 0, 1] + permute_dict = dict_fn.permute(indices) + permute_vect = vec_fn.permute(indices) + + equivalent = np.allclose(permute_dict.to_matrix(), permute_vect.to_matrix()) + self.assertTrue(equivalent) + def test_compose_consistency(self): """Test if PrimitiveOp @ ComposedOp is consistent with ComposedOp @ PrimitiveOp.""" From 7ee9ee57b3ef9d3786027f388f6a3caa0c216269 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 21:44:53 +0200 Subject: [PATCH 39/91] fixed linting --- qiskit/aqua/operators/state_fns/dict_state_fn.py | 9 +++++++-- qiskit/aqua/operators/state_fns/operator_state_fn.py | 10 ---------- qiskit/aqua/operators/state_fns/state_fn.py | 10 ++++++++++ qiskit/aqua/operators/state_fns/vector_state_fn.py | 9 +++++++-- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index c33a7f3149..1bfe4c9605 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -23,6 +23,7 @@ from qiskit.circuit import ParameterExpression from qiskit.aqua import aqua_globals, AquaError +from .. import VectorStateFn # pylint: disable=cyclic-import from ..operator_base import OperatorBase from .state_fn import StateFn from ..list_ops.list_op import ListOp @@ -130,11 +131,16 @@ def expand_with_identity(self, num_qubits: int) -> 'DictStateFn': return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def to_vector_state_fn(self) -> 'VectorStateFn': + r""" + Creates the equivalent state function of type VectorStateFn. + + Returns: + A new VectorStateFn equivalent to ``self``. + """ states = int(2 ** self.num_qubits) probs = np.zeros(states) + 0.j for k, v in self.primitive.items(): probs[int(k, 2)] = v - from qiskit.aqua.operators import VectorStateFn return VectorStateFn(probs, coeff=self.coeff, is_measurement=self.is_measurement) def tensor(self, other: OperatorBase) -> OperatorBase: @@ -240,7 +246,6 @@ def eval(self, # All remaining possibilities only apply when self.is_measurement is True - from .vector_state_fn import VectorStateFn if isinstance(front, VectorStateFn): # TODO does it need to be this way for measurement? # return sum([v * front.primitive.data[int(b, 2)] * diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index fcf08b3221..eb45d5ff3c 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -88,16 +88,6 @@ def expand_with_identity(self, num_qubits: int) -> 'OperatorStateFn': is_measurement=self.is_measurement) def permute(self, permutation: List[int]) -> 'OperatorStateFn': - r""" - 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 OperatorStateFn containing the permuted operator. - """ return OperatorStateFn(self.primitive.permute(permutation), coeff=self.coeff, is_measurement=self.is_measurement) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 30b2a0b6a0..9235487d30 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -146,6 +146,16 @@ def expand_with_identity(self, num_qubits: int) -> 'StateFn': raise NotImplementedError def permute(self, permutation: List[int]) -> 'OperatorBase': + r""" + Permute the qubits of the state function. + + Args: + permutation: A list defining where each qubit should be permuted. The qubit at index + j of the circuit should be permuted to position permutation[j]. + + Returns: + A new StateFn containing the permuted primitive. + """ raise NotImplementedError def equals(self, other: OperatorBase) -> bool: diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 726690092b..f2d67b970a 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -22,6 +22,7 @@ from qiskit.circuit import ParameterExpression from qiskit.aqua import aqua_globals +from .. import DictStateFn # pylint: disable=cyclic-import from ..operator_base import OperatorBase from .state_fn import StateFn from ..list_ops.list_op import ListOp @@ -82,9 +83,14 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': return self.to_dict_fn().permute(permutation).to_vector_state_fn() def to_dict_fn(self) -> 'DictStateFn': + r""" + Creates the equivalent state function of type DictStateFn. + + Returns: + A new DictStateFn equivalent to ``self``. + """ num_qubits = self.num_qubits new_dict = {format(i, 'b').zfill(num_qubits): v for i, v in enumerate(self.primitive.data)} - from qiskit.aqua.operators import DictStateFn return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def expand_with_identity(self, num_qubits: int) -> 'VectorStateFn': @@ -159,7 +165,6 @@ def eval(self, # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import EVAL_SIG_DIGITS - from .dict_state_fn import DictStateFn from .operator_state_fn import OperatorStateFn from .circuit_state_fn import CircuitStateFn if isinstance(front, DictStateFn): From 0e03efe07b4cbc2c5ea60918207b418127c2f165 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 6 Aug 2020 23:19:01 +0200 Subject: [PATCH 40/91] cyclic import solved --- qiskit/aqua/operators/list_ops/tensored_op.py | 2 +- qiskit/aqua/operators/state_fns/dict_state_fn.py | 4 ++-- qiskit/aqua/operators/state_fns/vector_state_fn.py | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index d7702cd8f0..9eb59d80eb 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -59,7 +59,7 @@ def expand_with_identity(self, num_qubits: int) -> 'TensoredOp': identity is arbitrary and can be substituted for other PrimitiveOp identity. Returns: - Identity operator represented by PauliOp. + TensoredOp expanded with identity operator. """ from qiskit.aqua.operators import PauliOp return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))], coeff=self.coeff) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 1bfe4c9605..381130c995 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -23,10 +23,10 @@ from qiskit.circuit import ParameterExpression from qiskit.aqua import aqua_globals, AquaError -from .. import VectorStateFn # pylint: disable=cyclic-import from ..operator_base import OperatorBase from .state_fn import StateFn from ..list_ops.list_op import ListOp +from .vector_state_fn import VectorStateFn class DictStateFn(StateFn): @@ -130,7 +130,7 @@ def expand_with_identity(self, num_qubits: int) -> 'DictStateFn': new_dict = {key + pad: value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) - def to_vector_state_fn(self) -> 'VectorStateFn': + def to_vector_state_fn(self) -> 'VectorStateFn': # type: ignore r""" Creates the equivalent state function of type VectorStateFn. diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index f2d67b970a..f99b6b8e15 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -22,7 +22,6 @@ from qiskit.circuit import ParameterExpression from qiskit.aqua import aqua_globals -from .. import DictStateFn # pylint: disable=cyclic-import from ..operator_base import OperatorBase from .state_fn import StateFn from ..list_ops.list_op import ListOp @@ -82,13 +81,15 @@ def adjoint(self) -> OperatorBase: def permute(self, permutation: List[int]) -> 'OperatorBase': return self.to_dict_fn().permute(permutation).to_vector_state_fn() - def to_dict_fn(self) -> 'DictStateFn': + def to_dict_fn(self) -> 'DictStateFn': # type: ignore r""" Creates the equivalent state function of type DictStateFn. Returns: A new DictStateFn equivalent to ``self``. """ + from .dict_state_fn import DictStateFn + num_qubits = self.num_qubits new_dict = {format(i, 'b').zfill(num_qubits): v for i, v in enumerate(self.primitive.data)} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) @@ -167,6 +168,7 @@ def eval(self, from ..operator_globals import EVAL_SIG_DIGITS from .operator_state_fn import OperatorStateFn from .circuit_state_fn import CircuitStateFn + from .dict_state_fn import DictStateFn if isinstance(front, DictStateFn): return np.round(sum([v * self.primitive.data[int(b, 2)] * front.coeff # type: ignore for (b, v) in front.primitive.items()]) * self.coeff, From 1ef1b30e0e64534e186c6d679c71033d87ed22bf Mon Sep 17 00:00:00 2001 From: molar-volume Date: Fri, 7 Aug 2020 09:16:35 +0200 Subject: [PATCH 41/91] fixed linting --- qiskit/aqua/operators/state_fns/vector_state_fn.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index f99b6b8e15..77f5f911fc 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -78,10 +78,10 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def permute(self, permutation: List[int]) -> 'OperatorBase': - return self.to_dict_fn().permute(permutation).to_vector_state_fn() + def permute(self, permutation: List[int]) -> 'VectorStateFn': + return self.to_dict_fn().permute(permutation).to_vector_state_fn() # type: ignore - def to_dict_fn(self) -> 'DictStateFn': # type: ignore + def to_dict_fn(self) -> 'StateFn': r""" Creates the equivalent state function of type DictStateFn. From d856698ca9c5195fae3d21b029e730208fef6686 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Fri, 7 Aug 2020 17:23:26 +0200 Subject: [PATCH 42/91] 1) more unit tests for compose of StateFn with indices 2) fix on StateFn composition --- qiskit/aqua/operators/state_fns/state_fn.py | 3 ++- test/aqua/operators/test_op_construction.py | 26 +++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 9235487d30..18edc418af 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -264,7 +264,8 @@ def compose(self, other: OperatorBase, raise ValueError( 'Composition with a Statefunction in the first operand is not defined.') - new_self, other = self._check_zero_for_composition_and_expand(other) + new_self, other = self._check_zero_for_composition_and_expand(other, permute_self, + permute_other) # TODO maybe include some reduction here in the subclasses - vector and Op, op and Op, etc. # pylint: disable=import-outside-toplevel from qiskit.aqua.operators import CircuitOp diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index e81eef88bb..3b65bde4a1 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -580,8 +580,9 @@ def test_compose_with_indices(self): # with permutation num_qubits = 5 indices = [1, 4] - permuted_primitive_op = pauli_op @ circuit_op.permute(indices) @ matrix_op - composed_primitive_op = pauli_op.compose(circuit_op, permute_other=indices) @ matrix_op + permuted_primitive_op = evolved_op @ pauli_op @ circuit_op.permute(indices) @ matrix_op + composed_primitive_op = \ + evolved_op @ pauli_op.compose(circuit_op, permute_other=indices) @ matrix_op self.assertTrue(np.allclose(permuted_primitive_op.to_matrix(), composed_primitive_op.to_matrix())) @@ -607,6 +608,27 @@ def test_compose_with_indices(self): perm_op = circuit_fn.compose(operator_fn, permute_self=indices) self.assertEqual(perm_op.num_qubits, max(indices) + 1) + # StateFn + num_qubits = 3 + dim = 2**num_qubits + vec = [1.0/(i+1) for i in range(dim)] + dic = {format(i, 'b').zfill(num_qubits): 1.0/(i+1) for i in range(dim)} + + is_measurement = True + op_state_fn = OperatorStateFn(matrix_op, is_measurement=is_measurement) # num_qubit = 4 + vec_state_fn = VectorStateFn(vec, is_measurement=is_measurement) # 3 + dic_state_fn = DictStateFn(dic, is_measurement=is_measurement) # 3 + circ_state_fn = CircuitStateFn(circuit_op.to_circuit(), is_measurement=is_measurement) # 2 + + composed_op = op_state_fn @ vec_state_fn @ dic_state_fn @ circ_state_fn + self.assertEqual(composed_op.num_qubits, op_state_fn.num_qubits) + + # with permutation + perm = [2, 4, 6] + composed = \ + op_state_fn @ vec_state_fn.compose(dic_state_fn, permute_self=perm) @ circ_state_fn + self.assertEqual(composed.num_qubits, max(perm) + 1) + def test_summed_op_equals(self): """Test corner cases of SummedOp's equals function.""" with self.subTest('multiplicative factor'): From 3098688b730d40812b5c6ac3810b1172c0cfda75 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Mon, 10 Aug 2020 19:35:20 +0200 Subject: [PATCH 43/91] Update qiskit/aqua/operators/evolutions/evolved_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/evolutions/evolved_op.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index b8fa9f7357..20017465c8 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -90,8 +90,8 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': - from qiskit.quantum_info import Pauli - return self.tensor(PauliOp(Pauli(label='I'*num_qubits))) + from qiskit.aqua.operators import I + return self.tensor(I ^ num_qubits) def permute(self, permutation: List[int]) -> 'OperatorBase': return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore From 133d4ef24d7bad427873d13f989685d43e58cf04 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Mon, 10 Aug 2020 20:28:03 +0200 Subject: [PATCH 44/91] Update qiskit/aqua/operators/list_ops/list_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/list_ops/list_op.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 5964225187..13e59c1c5b 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -21,8 +21,7 @@ from scipy.sparse import spmatrix from sympy.combinatorics import Permutation -from qiskit import QuantumCircuit -from qiskit.circuit import ParameterExpression +from qiskit.circuit import QuantumCircuit, ParameterExpression from ..legacy.base_operator import LegacyBaseOperator from ..operator_base import OperatorBase From fb9685c81cbcd586a7b64427d4fa32f5e303728b Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Mon, 10 Aug 2020 20:28:56 +0200 Subject: [PATCH 45/91] Update qiskit/aqua/operators/list_ops/list_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/list_ops/list_op.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 13e59c1c5b..63c20453bb 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -209,8 +209,7 @@ def expand_with_identity(self, num_qubits: int) -> 'ListOp': for op in self.oplist], combo_fn=self.combo_fn, coeff=self.coeff) def permute(self, permutation: List[int]) -> 'ListOp': - r""" - Permute the qubits of the operator. + """Permute the qubits of the operator. Args: permutation: A list defining where each qubit should be permuted. The qubit at index From d973e670cef525a8d164863e6a3af9f92baba32b Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Mon, 10 Aug 2020 20:34:27 +0200 Subject: [PATCH 46/91] Update qiskit/aqua/operators/primitive_ops/pauli_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 048a340971..b8e1c29a2f 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -102,7 +102,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def permute(self, permutation: List[int] = None) -> 'PauliOp': - """ Permutes the sequence of Pauli matrices. + """Permutes the sequence of Pauli matrices. Args: permutation: A list defining where each Pauli should be permuted. The Pauli at index From 8b6265ce4b6165d1e61b983447fc6cb502053fe8 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Mon, 10 Aug 2020 20:34:39 +0200 Subject: [PATCH 47/91] Update qiskit/aqua/operators/primitive_ops/matrix_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 4609c2b1bd..78c08ee824 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -134,7 +134,7 @@ def compose(self, other: OperatorBase, return super(MatrixOp, self).compose(other) def permute(self, permutation: List[int] = None) -> 'MatrixOp': - """ Creates a new MatrixOp that acts on the permuted qubits. + """Creates a new MatrixOp that acts on the permuted qubits. Args: permutation: A list defining where each qubit should be permuted. The qubit at index From 26ab16497833b3a689a615de218cdeaaf81bc9aa Mon Sep 17 00:00:00 2001 From: molar-volume Date: Mon, 10 Aug 2020 21:38:08 +0200 Subject: [PATCH 48/91] implemented custom function to decompose permutations into transpositions, to avoid import of sympy --- qiskit/aqua/operators/list_ops/list_op.py | 4 +-- .../aqua/operators/primitive_ops/matrix_op.py | 4 +-- qiskit/aqua/utils/arithmetic.py | 30 +++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 5964225187..fa92a8e0f0 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -19,7 +19,6 @@ import numpy as np from scipy.sparse import spmatrix -from sympy.combinatorics import Permutation from qiskit import QuantumCircuit from qiskit.circuit import ParameterExpression @@ -27,6 +26,7 @@ from ..legacy.base_operator import LegacyBaseOperator from ..operator_base import OperatorBase from ... import AquaError +from ...utils import arithmetic class ListOp(OperatorBase): @@ -237,7 +237,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': = list(filter(lambda x: x not in permutation, range(circuit_size))) + permutation # decompose permutation into sequence of transpositions - transpositions = Permutation(permutation).transpositions() + transpositions = arithmetic.transpositions(permutation) for trans in transpositions: qc.swap(trans[0], trans[1]) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 4609c2b1bd..91ede97033 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -18,7 +18,6 @@ import logging import numpy as np from scipy.sparse import spmatrix -from sympy.combinatorics import Permutation from qiskit import QuantumCircuit from qiskit.quantum_info import Operator @@ -31,6 +30,7 @@ from ..list_ops.tensored_op import TensoredOp from .primitive_op import PrimitiveOp from ..legacy.matrix_operator import MatrixOperator +from ...utils import arithmetic from ... import AquaError logger = logging.getLogger(__name__) @@ -161,7 +161,7 @@ def permute(self, permutation: List[int] = None) -> 'MatrixOp': = list(filter(lambda x: x not in permutation, range(new_matrix_size))) + permutation # decompose permutation into sequence of transpositions - transpositions = Permutation(permutation).transpositions() + transpositions = arithmetic.transpositions(permutation) for trans in transpositions: qc.swap(trans[0], trans[1]) matrix = CircuitOp(qc).to_matrix() diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index e613bd87ac..fe1defb770 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -95,3 +95,33 @@ def next_power_of_2_base(n): base += 1 return base + + +def transpositions(permutation): + """ + Return the permutation decomposed into a list of transpositions. + """ + unchecked = [True] * len(permutation) + cyclic_form = [] + for i in range(len(permutation)): + if unchecked[i]: + cycle = [i] + unchecked[i] = False + j = i + while unchecked[permutation[j]]: + j = permutation[j] + cycle.append(j) + unchecked[j] = False + if len(cycle) > 1: + cyclic_form.append(cycle) + cyclic_form.sort() + res = [] + for x in cyclic_form: + nx = len(x) + if nx == 2: + res.append(tuple(x)) + elif nx > 2: + first = x[0] + for y in x[nx - 1:0:-1]: + res.append((first, y)) + return res From d6950dc97abd9dcd76ef0350befcc523a3c95e72 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 19:07:29 +0200 Subject: [PATCH 49/91] explaining comment for CircuitStateFn.expand_with_identity --- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index a20005dace..99de0b5eac 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -360,6 +360,8 @@ def reduce(self) -> OperatorBase: return self def expand_with_identity(self, num_qubits: int) -> 'CircuitStateFn': + # this is equivalent to self.tensor(identity_operator), but optimized for better performance + # just like in tensor method, qiskit endianness is reversed here return self.permute(list(range(num_qubits, num_qubits + self.num_qubits))) def permute(self, permutation: List[int]) -> 'CircuitStateFn': From f341e828806cfb0e208ebc47dbb810af42c9d581 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 19:36:14 +0200 Subject: [PATCH 50/91] fix linting --- qiskit/aqua/utils/arithmetic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index fe1defb770..79f76b0b17 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -117,11 +117,11 @@ def transpositions(permutation): cyclic_form.sort() res = [] for x in cyclic_form: - nx = len(x) - if nx == 2: + len_x = len(x) + if len_x == 2: res.append(tuple(x)) - elif nx > 2: + elif len_x > 2: first = x[0] - for y in x[nx - 1:0:-1]: + for y in x[len_x - 1:0:-1]: res.append((first, y)) return res From 05c6fce1a73bee6d54c5ab492044a0ba38725ca1 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 19:44:36 +0200 Subject: [PATCH 51/91] expand_with_identity made private and renamed to _expand_dim (expand_with_identity is misleading for implementations in DictStateFn and VectorStateFn, where zeros are used for expansion) --- qiskit/aqua/operators/evolutions/evolved_op.py | 2 +- qiskit/aqua/operators/list_ops/list_op.py | 6 +++--- qiskit/aqua/operators/list_ops/tensored_op.py | 2 +- qiskit/aqua/operators/operator_base.py | 6 +++--- qiskit/aqua/operators/primitive_ops/circuit_op.py | 2 +- qiskit/aqua/operators/primitive_ops/matrix_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- .../aqua/operators/primitive_ops/primitive_op.py | 2 +- .../aqua/operators/state_fns/circuit_state_fn.py | 2 +- qiskit/aqua/operators/state_fns/dict_state_fn.py | 2 +- .../aqua/operators/state_fns/operator_state_fn.py | 4 ++-- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- qiskit/aqua/operators/state_fns/vector_state_fn.py | 2 +- test/aqua/operators/test_op_construction.py | 14 +++++++------- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 20017465c8..b76c800444 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -89,7 +89,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': + def _expand_dim(self, num_qubits: int) -> 'OperatorBase': from qiskit.aqua.operators import I return self.tensor(I ^ num_qubits) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index e48fad3697..263c650554 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -204,8 +204,8 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: from .tensored_op import TensoredOp return TensoredOp([self] * other) - def expand_with_identity(self, num_qubits: int) -> 'ListOp': - return ListOp([op.expand_with_identity(num_qubits + self.num_qubits - op.num_qubits) + 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': @@ -228,7 +228,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < circuit_size: # pad the operator with identities - new_self = self.expand_with_identity(circuit_size - self.num_qubits) + 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 \ diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 9eb59d80eb..9e622feaeb 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -54,7 +54,7 @@ def num_qubits(self) -> int: def distributive(self) -> bool: return False - def expand_with_identity(self, num_qubits: int) -> 'TensoredOp': + 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. diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 9394a6b01a..c2d6305526 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -443,7 +443,7 @@ def assign_parameters(self, raise NotImplementedError @abstractmethod - def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': + def _expand_dim(self, num_qubits: int) -> 'OperatorBase': r""" Expands the operator with identity operator of dimension 2**num_qubits. Returns: @@ -533,10 +533,10 @@ def _check_zero_for_composition_and_expand(self, other: 'OperatorBase', # 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_with_identity(self.num_qubits - other.num_qubits) + other = other._expand_dim(self.num_qubits - other.num_qubits) elif other.num_qubits > self.num_qubits: # type: ignore - new_self = self.expand_with_identity(other.num_qubits - self.num_qubits) + new_self = self._expand_dim(other.num_qubits - self.num_qubits) return new_self, other # Composition diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index e8b197a6f0..34c85765bb 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -232,7 +232,7 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] # type: ignore return self - def expand_with_identity(self, num_qubits: int) -> 'CircuitOp': + 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': diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index fb8f051fb0..9531ad8ad0 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -110,7 +110,7 @@ def equals(self, other: OperatorBase) -> bool: return self.coeff == other.coeff and self.primitive == other.primitive return self.coeff * self.primitive == other.coeff * other.primitive # type: ignore - def expand_with_identity(self, num_qubits: int) -> 'MatrixOp': + def _expand_dim(self, num_qubits: int) -> 'MatrixOp': identity = np.identity(2**num_qubits, dtype=complex) return MatrixOp(self.primitive.tensor(Operator(identity)), coeff=self.coeff) # type: ignore @@ -153,7 +153,7 @@ def permute(self, permutation: List[int] = None) -> 'MatrixOp': raise AquaError("New index must be defined for each qubit of the operator.") if self.num_qubits < new_matrix_size: # pad the operator with identities - new_self = self.expand_with_identity(new_matrix_size - self.num_qubits) + new_self = self._expand_dim(new_matrix_size - self.num_qubits) qc = QuantumCircuit(new_matrix_size) # extend the indices to match the size of the new matrix diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index b8e1c29a2f..1edcb909c7 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -83,7 +83,7 @@ def equals(self, other: OperatorBase) -> bool: return self.primitive == other.primitive - def expand_with_identity(self, num_qubits: int) -> 'PauliOp': + def _expand_dim(self, num_qubits: int) -> 'PauliOp': return PauliOp(Pauli(label='I'*num_qubits).kron(self.primitive), coeff=self.coeff) def tensor(self, other: OperatorBase) -> OperatorBase: diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index bdcc9bb0fe..76c0468f42 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -176,7 +176,7 @@ def power(self, exponent: int) -> OperatorBase: temp = temp.compose(self) return temp - def expand_with_identity(self, num_qubits: int) -> 'OperatorBase': + def _expand_dim(self, num_qubits: int) -> 'OperatorBase': raise NotImplementedError def permute(self, permutation: List[int]) -> 'OperatorBase': diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 99de0b5eac..7c39757024 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -359,7 +359,7 @@ def reduce(self) -> OperatorBase: del self.primitive.data[i] return self - def expand_with_identity(self, num_qubits: int) -> 'CircuitStateFn': + def _expand_dim(self, num_qubits: int) -> 'CircuitStateFn': # this is equivalent to self.tensor(identity_operator), but optimized for better performance # just like in tensor method, qiskit endianness is reversed here return self.permute(list(range(num_qubits, num_qubits + self.num_qubits))) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 381130c995..8b363d4373 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -125,7 +125,7 @@ def perm(key): new_dict = {perm(key): value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) - def expand_with_identity(self, num_qubits: int) -> 'DictStateFn': + def _expand_dim(self, num_qubits: int) -> 'DictStateFn': pad = '0'*num_qubits new_dict = {key + pad: value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) diff --git a/qiskit/aqua/operators/state_fns/operator_state_fn.py b/qiskit/aqua/operators/state_fns/operator_state_fn.py index eb45d5ff3c..f3a34ec242 100644 --- a/qiskit/aqua/operators/state_fns/operator_state_fn.py +++ b/qiskit/aqua/operators/state_fns/operator_state_fn.py @@ -82,8 +82,8 @@ def adjoint(self) -> OperatorBase: coeff=np.conj(self.coeff), is_measurement=(not self.is_measurement)) - def expand_with_identity(self, num_qubits: int) -> 'OperatorStateFn': - return OperatorStateFn(self.primitive.expand_with_identity(num_qubits), + def _expand_dim(self, num_qubits: int) -> 'OperatorStateFn': + return OperatorStateFn(self.primitive._expand_dim(num_qubits), coeff=self.coeff, is_measurement=self.is_measurement) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 18edc418af..1d61f471df 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -142,7 +142,7 @@ def add(self, other: OperatorBase) -> OperatorBase: def adjoint(self) -> OperatorBase: raise NotImplementedError - def expand_with_identity(self, num_qubits: int) -> 'StateFn': + def _expand_dim(self, num_qubits: int) -> 'StateFn': raise NotImplementedError def permute(self, permutation: List[int]) -> 'OperatorBase': diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 77f5f911fc..af9b43ec5f 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -94,7 +94,7 @@ def to_dict_fn(self) -> 'StateFn': new_dict = {format(i, 'b').zfill(num_qubits): v for i, v in enumerate(self.primitive.data)} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) - def expand_with_identity(self, num_qubits: int) -> 'VectorStateFn': + def _expand_dim(self, num_qubits: int) -> 'VectorStateFn': primitive = np.zeros(2**num_qubits, dtype=complex) return VectorStateFn(self.primitive.tensor(primitive), coeff=self.coeff, diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 3b65bde4a1..8f537895ec 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -462,17 +462,17 @@ def test_expand_on_list_op(self): # ComposedOp composed_op = ComposedOp([(X ^ Y ^ Z), (H ^ T), (Z ^ X ^ Y ^ Z).to_matrix_op()]) - expanded = composed_op.expand_with_identity(add_qubits) + expanded = composed_op._expand_dim(add_qubits) self.assertEqual(composed_op.num_qubits + add_qubits, expanded.num_qubits) # TensoredOp tensored_op = TensoredOp([(X ^ Y), (Z ^ I)]) - expanded = tensored_op.expand_with_identity(add_qubits) + expanded = tensored_op._expand_dim(add_qubits) self.assertEqual(tensored_op.num_qubits + add_qubits, expanded.num_qubits) # SummedOp summed_op = SummedOp([(X ^ Y), (Z ^ I ^ Z)]) - expanded = summed_op.expand_with_identity(add_qubits) + expanded = summed_op._expand_dim(add_qubits) self.assertEqual(summed_op.num_qubits + add_qubits, expanded.num_qubits) def test_expand_on_state_fn(self): @@ -486,12 +486,12 @@ def test_expand_on_state_fn(self): cfn = CircuitStateFn(qc2, is_measurement=True) - cfn_exp = cfn.expand_with_identity(add_qubits) + cfn_exp = cfn._expand_dim(add_qubits) self.assertEqual(cfn_exp.num_qubits, add_qubits + num_qubits) # case OperatorStateFn, with OperatorBase primitive, in our case CircuitStateFn osfn = OperatorStateFn(cfn) - osfn_exp = osfn.expand_with_identity(add_qubits) + osfn_exp = osfn._expand_dim(add_qubits) self.assertEqual(osfn_exp.num_qubits, add_qubits + num_qubits) @@ -499,14 +499,14 @@ def test_expand_on_state_fn(self): dsfn = DictStateFn('1'*num_qubits, is_measurement=True) self.assertEqual(dsfn.num_qubits, num_qubits) - dsfn_exp = dsfn.expand_with_identity(add_qubits) + dsfn_exp = dsfn._expand_dim(add_qubits) self.assertEqual(dsfn_exp.num_qubits, num_qubits + add_qubits) # case VectorStateFn vsfn = VectorStateFn(np.ones(2**num_qubits, dtype=complex)) self.assertEqual(vsfn.num_qubits, num_qubits) - vsfn_exp = vsfn.expand_with_identity(add_qubits) + vsfn_exp = vsfn._expand_dim(add_qubits) self.assertEqual(vsfn_exp.num_qubits, num_qubits + add_qubits) def test_permute_on_state_fn(self): From bf82719af00fd9397b6fdd81519562419fe6aa9f Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 20:40:20 +0200 Subject: [PATCH 52/91] 1) Compose method has only one set of permutation indices (for other operator). 2) Added new argument front=False in compose method. If front==True, return other.compose(self), but only after expansion and permutation is performed. --- qiskit/aqua/operators/evolutions/evolved_op.py | 7 ++++--- qiskit/aqua/operators/list_ops/composed_op.py | 7 ++++--- qiskit/aqua/operators/list_ops/list_op.py | 7 ++++--- qiskit/aqua/operators/operator_base.py | 16 ++++++---------- .../aqua/operators/primitive_ops/circuit_op.py | 7 ++++--- qiskit/aqua/operators/primitive_ops/matrix_op.py | 7 ++++--- qiskit/aqua/operators/primitive_ops/pauli_op.py | 7 ++++--- .../aqua/operators/primitive_ops/primitive_op.py | 3 +-- .../aqua/operators/state_fns/circuit_state_fn.py | 11 ++++++----- qiskit/aqua/operators/state_fns/state_fn.py | 15 ++++++--------- qiskit/aqua/utils/arithmetic.py | 2 +- 11 files changed, 44 insertions(+), 45 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index b76c800444..4570f934f9 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -97,11 +97,12 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permute_self, permute_other) + permutation) + if front: + return other.compose(self) if isinstance(other, ComposedOp): return ComposedOp([self] + other.oplist) # type: ignore diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 41d1e84e97..c0b385fc90 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -66,11 +66,12 @@ def adjoint(self) -> OperatorBase: return ComposedOp([op.adjoint() for op in reversed(self.oplist)], coeff=self.coeff) def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permute_self, permute_other) + permutation) + if front: + return other.compose(self) # Try composing with last element in list if isinstance(other, ComposedOp): return ComposedOp(self.oplist + other.oplist, coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 263c650554..3d65a83b6b 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -244,11 +244,12 @@ def permute(self, permutation: List[int]) -> 'ListOp': return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc) # type: ignore def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permute_self, permute_other) + permutation) + if front: + return other.compose(self) # Avoid circular dependency # pylint: disable=cyclic-import,import-outside-toplevel from .composed_op import ComposedOp diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index c2d6305526..e539cd57d2 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -518,13 +518,10 @@ def _get_param_dict_for_index(unrolled_dict: Dict[ParameterExpression, List[Numb return {k: v[i] for (k, v) in unrolled_dict.items()} def _check_zero_for_composition_and_expand(self, other: 'OperatorBase', - permute_self: List[int] = None, - permute_other: List[int] = None) \ + permutation: List[int] = None) \ -> Tuple['OperatorBase', 'OperatorBase']: - if permute_self is not None: - self = self.permute(permute_self) # pylint: disable=self-cls-assignment - if permute_other is not None: - other = other.permute(permute_other) + if permutation is not None: + other = other.permute(permutation) new_self = self if not self.num_qubits == other.num_qubits: # pylint: disable=cyclic-import,import-outside-toplevel @@ -554,8 +551,7 @@ def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase': @abstractmethod def compose(self, other: 'OperatorBase', - permute_self: List[int] = None, - permute_other: List[int] = None) -> 'OperatorBase': + permutation: List[int] = None, front=False) -> 'OperatorBase': r""" Return Operator Composition between self and other (linear algebra-style: A@B(x) = A(B(x))), overloaded by ``@``. @@ -569,8 +565,8 @@ def compose(self, other: 'OperatorBase', Args: other: The ``OperatorBase`` with which to compose self. - permute_self: ``List[int]`` which defines permutation on self. - permute_other: ``List[int]`` which defines permutation on other. + 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. diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 34c85765bb..ba076f83f1 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -110,11 +110,12 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permute_self, permute_other) + permutation) + if front: + return other.compose(self) # ignore # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 9531ad8ad0..4d510f14ac 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -122,11 +122,12 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permute_self, permute_other) + permutation) + if front: + return other.compose(self) if isinstance(other, MatrixOp): return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore coeff=self.coeff * other.coeff) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 1edcb909c7..1290f95ab9 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -125,11 +125,12 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permute_self, permute_other) + permutation) + if front: + other.compose(self) # If self is identity, just return other. if not any(self.primitive.x + self.primitive.z): # type: ignore return other * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 76c0468f42..e90700f317 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -156,8 +156,7 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: from ..list_ops.composed_op import ComposedOp if isinstance(other, ComposedOp): comp_with_first = self.compose(other.oplist[0]) diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 7c39757024..245c04944e 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -140,14 +140,15 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: - if not self.is_measurement: + permutation: List[int] = None, front=False) -> OperatorBase: + if not self.is_measurement and not front: raise ValueError( 'Composition with a Statefunctions in the first operand is not defined.') # type: ignore - new_self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + new_self, other = self._check_zero_for_composition_and_expand(other, permutation) + + if front: + return other.compose(new_self) # pylint: disable=cyclic-import,import-outside-toplevel from ..primitive_ops.circuit_op import CircuitOp diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 1d61f471df..f00a676ee9 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -207,8 +207,7 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def _check_zero_for_composition_and_expand(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) \ + permutation: List[int] = None) \ -> Tuple[OperatorBase, OperatorBase]: from qiskit.aqua.operators import Zero @@ -220,7 +219,7 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase, # Zero is special - we'll expand it to the correct qubit number. return self, StateFn('0' * self.num_qubits) - return super()._check_zero_for_composition_and_expand(other, permute_self, permute_other) + return super()._check_zero_for_composition_and_expand(other, permutation) def to_matrix(self, massive: bool = False) -> np.ndarray: raise NotImplementedError @@ -242,16 +241,15 @@ def to_density_matrix(self, massive: bool = False) -> np.ndarray: raise NotImplementedError def compose(self, other: OperatorBase, - permute_self: List[int] = None, - permute_other: List[int] = None) -> OperatorBase: + permutation: List[int] = None, front=False) -> OperatorBase: r""" Composition (Linear algebra-style: A@B(x) = A(B(x))) is not well defined for states in the binary function model, but is well defined for measurements. Args: other: The Operator to compose with self. - permute_self: ``List[int]`` which defines permutation on self. - permute_other: ``List[int]`` which defines permutation on other. + permutation: ``List[int]`` which defines permutation on other operator. + front: If front==True, return ``other.compose(self)``. Returns: An Operator equivalent to the function composition of self and other. @@ -264,8 +262,7 @@ def compose(self, other: OperatorBase, raise ValueError( 'Composition with a Statefunction in the first operand is not defined.') - new_self, other = self._check_zero_for_composition_and_expand(other, permute_self, - permute_other) + new_self, other = self._check_zero_for_composition_and_expand(other, permutation) # TODO maybe include some reduction here in the subclasses - vector and Op, op and Op, etc. # pylint: disable=import-outside-toplevel from qiskit.aqua.operators import CircuitOp diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index 79f76b0b17..0ff5b9da15 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -2,7 +2,7 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2019. +# (C) Copyright IBM 2019, 2020. # # 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 From dabf7c6888ff5fc9d42d147e46bc91549d7b1dce Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 21:00:22 +0200 Subject: [PATCH 53/91] 1) modified test_op_construction because of changes in compose signature 2) fix in CircuitOp.compose --- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- qiskit/aqua/operators/state_fns/state_fn.py | 5 ++++- test/aqua/operators/test_op_construction.py | 12 +++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 1290f95ab9..0a5ae0a829 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -130,7 +130,7 @@ def compose(self, other: OperatorBase, self, other = self._check_zero_for_composition_and_expand(other, # type: ignore permutation) if front: - other.compose(self) + return other.compose(self) # If self is identity, just return other. if not any(self.primitive.x + self.primitive.z): # type: ignore return other * self.coeff # type: ignore diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index f00a676ee9..6a40185393 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -258,11 +258,14 @@ def compose(self, other: OperatorBase, ValueError: If self is not a measurement, it cannot be composed from the right. """ # TODO maybe allow outers later to produce density operators or projectors, but not yet. - if not self.is_measurement: + if not self.is_measurement and not front: raise ValueError( 'Composition with a Statefunction in the first operand is not defined.') new_self, other = self._check_zero_for_composition_and_expand(other, permutation) + + if front: + return other.compose(self) # TODO maybe include some reduction here in the subclasses - vector and Op, op and Op, etc. # pylint: disable=import-outside-toplevel from qiskit.aqua.operators import CircuitOp diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 8f537895ec..60a5b79086 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -580,9 +580,9 @@ def test_compose_with_indices(self): # with permutation num_qubits = 5 indices = [1, 4] - permuted_primitive_op = evolved_op @ pauli_op @ circuit_op.permute(indices) @ matrix_op + permuted_primitive_op = evolved_op @ circuit_op.permute(indices) @ pauli_op @ matrix_op composed_primitive_op = \ - evolved_op @ pauli_op.compose(circuit_op, permute_other=indices) @ matrix_op + evolved_op @ pauli_op.compose(circuit_op, permutation=indices, front=True) @ matrix_op self.assertTrue(np.allclose(permuted_primitive_op.to_matrix(), composed_primitive_op.to_matrix())) @@ -594,7 +594,8 @@ def test_compose_with_indices(self): summed_op = pauli_op + circuit_op.permute([2, 1]) composed_op = circuit_op @ evolved_op @ matrix_op - list_op = summed_op @ tensored_op.compose(composed_op, permute_self=[1, 2, 3, 5, 4]) + list_op = summed_op @ composed_op.compose(tensored_op, permutation=[1, 2, 3, 5, 4], + front=True) self.assertEqual(num_qubits, list_op.num_qubits) num_qubits = 4 @@ -605,7 +606,7 @@ def test_compose_with_indices(self): self.assertEqual(no_perm_op.num_qubits, num_qubits) indices = [0, 4] - perm_op = circuit_fn.compose(operator_fn, permute_self=indices) + perm_op = operator_fn.compose(circuit_fn, permutation=indices, front=True) self.assertEqual(perm_op.num_qubits, max(indices) + 1) # StateFn @@ -626,7 +627,8 @@ def test_compose_with_indices(self): # with permutation perm = [2, 4, 6] composed = \ - op_state_fn @ vec_state_fn.compose(dic_state_fn, permute_self=perm) @ circ_state_fn + op_state_fn @ dic_state_fn.compose(vec_state_fn, permutation=perm, front=True) @ \ + circ_state_fn self.assertEqual(composed.num_qubits, max(perm) + 1) def test_summed_op_equals(self): From 13427351924308cf6f6d6682a8ba40930c009baf Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 21:58:22 +0200 Subject: [PATCH 54/91] _check_zero_for_composition_and_expand renamed to _expand_shorter_operator_and_permute, to be more self-explanatory --- qiskit/aqua/operators/evolutions/evolved_op.py | 4 ++-- qiskit/aqua/operators/list_ops/composed_op.py | 4 ++-- qiskit/aqua/operators/list_ops/list_op.py | 4 ++-- qiskit/aqua/operators/operator_base.py | 4 ++-- qiskit/aqua/operators/primitive_ops/circuit_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/matrix_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/pauli_op.py | 4 ++-- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 2 +- qiskit/aqua/operators/state_fns/state_fn.py | 8 ++++---- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 4570f934f9..19a133b91a 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -99,8 +99,8 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': def compose(self, other: OperatorBase, permutation: List[int] = None, front=False) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permutation) + self, other = self._expand_shorter_operator_and_permute(other, # type: ignore + permutation) if front: return other.compose(self) if isinstance(other, ComposedOp): diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index c0b385fc90..33552038dd 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -68,8 +68,8 @@ def adjoint(self) -> OperatorBase: def compose(self, other: OperatorBase, permutation: List[int] = None, front=False) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permutation) + self, other = self._expand_shorter_operator_and_permute(other, # type: ignore + permutation) if front: return other.compose(self) # Try composing with last element in list diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 3d65a83b6b..ead51901b0 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -246,8 +246,8 @@ def permute(self, permutation: List[int]) -> 'ListOp': def compose(self, other: OperatorBase, permutation: List[int] = None, front=False) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permutation) + self, other = self._expand_shorter_operator_and_permute(other, # type: ignore + permutation) if front: return other.compose(self) # Avoid circular dependency diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index e539cd57d2..e6a1b65fad 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -517,8 +517,8 @@ 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 _check_zero_for_composition_and_expand(self, other: 'OperatorBase', - permutation: List[int] = None) \ + def _expand_shorter_operator_and_permute(self, other: 'OperatorBase', + permutation: List[int] = None) \ -> Tuple['OperatorBase', 'OperatorBase']: if permutation is not None: other = other.permute(permutation) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index ba076f83f1..4ba9c26936 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -112,8 +112,8 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permutation: List[int] = None, front=False) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permutation) + self, other = self._expand_shorter_operator_and_permute(other, # type: ignore + permutation) if front: return other.compose(self) # ignore diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 4d510f14ac..81e71b896c 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -124,8 +124,8 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permutation: List[int] = None, front=False) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permutation) + self, other = self._expand_shorter_operator_and_permute(other, # type: ignore + permutation) if front: return other.compose(self) if isinstance(other, MatrixOp): diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 0a5ae0a829..849ad8e414 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -127,8 +127,8 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': def compose(self, other: OperatorBase, permutation: List[int] = None, front=False) -> OperatorBase: - self, other = self._check_zero_for_composition_and_expand(other, # type: ignore - permutation) + self, other = self._expand_shorter_operator_and_permute(other, # type: ignore + permutation) if front: return other.compose(self) # If self is identity, just return other. diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 245c04944e..fece71189c 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -145,7 +145,7 @@ def compose(self, other: OperatorBase, raise ValueError( 'Composition with a Statefunctions in the first operand is not defined.') # type: ignore - new_self, other = self._check_zero_for_composition_and_expand(other, permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) if front: return other.compose(new_self) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 6a40185393..a0500bc280 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -206,8 +206,8 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp - def _check_zero_for_composition_and_expand(self, other: OperatorBase, - permutation: List[int] = None) \ + def _expand_shorter_operator_and_permute(self, other: OperatorBase, + permutation: List[int] = None) \ -> Tuple[OperatorBase, OperatorBase]: from qiskit.aqua.operators import Zero @@ -219,7 +219,7 @@ def _check_zero_for_composition_and_expand(self, other: OperatorBase, # Zero is special - we'll expand it to the correct qubit number. return self, StateFn('0' * self.num_qubits) - return super()._check_zero_for_composition_and_expand(other, permutation) + return super()._expand_shorter_operator_and_permute(other, permutation) def to_matrix(self, massive: bool = False) -> np.ndarray: raise NotImplementedError @@ -262,7 +262,7 @@ def compose(self, other: OperatorBase, raise ValueError( 'Composition with a Statefunction in the first operand is not defined.') - new_self, other = self._check_zero_for_composition_and_expand(other, permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) if front: return other.compose(self) From 998bf038547423fe2feb28bcd484a35fb617a819 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Tue, 11 Aug 2020 22:20:03 +0200 Subject: [PATCH 55/91] VectorStateFn.permute reimplemented for better performance --- .../operators/state_fns/vector_state_fn.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index af9b43ec5f..317745d813 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -17,14 +17,17 @@ from typing import Union, Set, List import numpy as np +from qiskit import QuantumCircuit from qiskit.quantum_info import Statevector from qiskit.circuit import ParameterExpression from qiskit.aqua import aqua_globals +from .. import CircuitOp from ..operator_base import OperatorBase from .state_fn import StateFn from ..list_ops.list_op import ListOp +from ...utils import arithmetic class VectorStateFn(StateFn): @@ -79,7 +82,30 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def permute(self, permutation: List[int]) -> 'VectorStateFn': - return self.to_dict_fn().permute(permutation).to_vector_state_fn() # type: ignore + new_self = self + new_num_qubits = max(permutation) + 1 + + if self.num_qubits != len(permutation): + # raise AquaError("New index must be defined for each qubit of the operator.") + pass + if self.num_qubits < new_num_qubits: + # pad the operator with identities + new_self = self._expand_dim(new_num_qubits - self.num_qubits) + qc = QuantumCircuit(new_num_qubits) + + # extend the permutation indices to match the size of the new matrix + permutation \ + = list(filter(lambda x: x not in permutation, range(new_num_qubits))) + permutation + + # decompose permutation into sequence of transpositions + transpositions = arithmetic.transpositions(permutation) + for trans in transpositions: + qc.swap(trans[0], trans[1]) + matrix = CircuitOp(qc).to_matrix() + vector = new_self.primitive.data + return VectorStateFn(primitive=matrix.dot(vector), + coeff=self.coeff, + is_measurement=self.is_measurement) def to_dict_fn(self) -> 'StateFn': r""" From 2301114a6070ceb18d87865b8f1b41951cf93fde Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 12 Aug 2020 20:58:04 +0200 Subject: [PATCH 56/91] type hint added for front parameter of compose --- qiskit/aqua/operators/evolutions/evolved_op.py | 2 +- qiskit/aqua/operators/list_ops/composed_op.py | 2 +- qiskit/aqua/operators/list_ops/list_op.py | 2 +- qiskit/aqua/operators/operator_base.py | 2 +- qiskit/aqua/operators/primitive_ops/circuit_op.py | 2 +- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- qiskit/aqua/operators/primitive_ops/primitive_op.py | 2 +- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 2 +- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 19a133b91a..c3f89e0d19 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -97,7 +97,7 @@ def permute(self, permutation: List[int]) -> 'OperatorBase': return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 33552038dd..2bdd2c6d9c 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -66,7 +66,7 @@ def adjoint(self) -> OperatorBase: return ComposedOp([op.adjoint() for op in reversed(self.oplist)], coeff=self.coeff) def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index ead51901b0..f72e4ede4a 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -244,7 +244,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc) # type: ignore def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index e6a1b65fad..24d99d4a1c 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -551,7 +551,7 @@ def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase': @abstractmethod def compose(self, other: 'OperatorBase', - permutation: List[int] = None, front=False) -> 'OperatorBase': + permutation: 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 ``@``. diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 4ba9c26936..290e4cefd3 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -110,7 +110,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 81e71b896c..64a3995f61 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -122,7 +122,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 849ad8e414..e799b9081b 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -125,7 +125,7 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index e90700f317..23bb41c288 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -156,7 +156,7 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: from ..list_ops.composed_op import ComposedOp if isinstance(other, ComposedOp): comp_with_first = self.compose(other.oplist[0]) diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index fece71189c..ba4542cb71 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -140,7 +140,7 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: if not self.is_measurement and not front: raise ValueError( 'Composition with a Statefunctions in the first operand is not defined.') diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index a0500bc280..cfd8e6dc6b 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -241,7 +241,7 @@ def to_density_matrix(self, massive: bool = False) -> np.ndarray: raise NotImplementedError def compose(self, other: OperatorBase, - permutation: List[int] = None, front=False) -> OperatorBase: + permutation: List[int] = None, front: bool = False) -> OperatorBase: r""" Composition (Linear algebra-style: A@B(x) = A(B(x))) is not well defined for states in the binary function model, but is well defined for measurements. From 793f56d7e85910b0f38638b5a4bbb81786279c75 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 12 Aug 2020 21:39:03 +0200 Subject: [PATCH 57/91] fixed linting after merge --- qiskit/aqua/operators/primitive_ops/primitive_op.py | 1 - test/aqua/operators/test_op_construction.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 15c502da20..23bb41c288 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -155,7 +155,6 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: temp = temp.tensor(self) return temp - def compose(self, other: OperatorBase, permutation: List[int] = None, front: bool = False) -> OperatorBase: from ..list_ops.composed_op import ComposedOp diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 25b25c206d..60a5b79086 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -703,6 +703,7 @@ def test_op_indent(self, op): ).split("\n{}".format(op.INDENTATION)) self.assertListEqual(indented_str_content, initial_str.split("\n")) + class TestListOpComboFn(QiskitAquaTestCase): """Test combo fn is propagated.""" From 709b0a5ba304495e4cb6f264da97898bcc92104c Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 12 Aug 2020 22:33:25 +0200 Subject: [PATCH 58/91] for arithmetic.transpositions, typehint for argument and docstring describing the method added --- qiskit/aqua/utils/arithmetic.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index 0ff5b9da15..09be39814b 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -17,6 +17,7 @@ """ import numpy as np +from typing import List def normalize_vector(vector): @@ -97,9 +98,16 @@ def next_power_of_2_base(n): return base -def transpositions(permutation): - """ - Return the permutation decomposed into a list of transpositions. +def transpositions(permutation: List[int]): + """Return a sequence of transpositions, corresponding to the permutation. + + Args: + permutation: The ``List[int]`` defining the permutation. An element at index ``j`` should be + permuted to index ``permutation[j]``. + + Returns: + List of transpositions, corresponding to the permutation. For permutation = [3, 0, 2, 1], + returns [ (0,1), (0,3) ] """ unchecked = [True] * len(permutation) cyclic_form = [] From ee2d597376a56f3899f52197811a8de668bf2176 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 12 Aug 2020 22:51:35 +0200 Subject: [PATCH 59/91] removed unnecessary apostrophes from return types --- qiskit/aqua/operators/evolutions/evolved_op.py | 4 ++-- qiskit/aqua/operators/list_ops/list_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/primitive_op.py | 4 ++-- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- qiskit/aqua/operators/state_fns/vector_state_fn.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index c3f89e0d19..5385989ff6 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -89,11 +89,11 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def _expand_dim(self, num_qubits: int) -> 'OperatorBase': + 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': + def permute(self, permutation: List[int]) -> OperatorBase: return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore def compose(self, other: OperatorBase, diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index f72e4ede4a..c853b73273 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -286,8 +286,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 diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 23bb41c288..619c29bf37 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -175,10 +175,10 @@ def power(self, exponent: int) -> OperatorBase: temp = temp.compose(self) return temp - def _expand_dim(self, num_qubits: int) -> 'OperatorBase': + def _expand_dim(self, num_qubits: int) -> OperatorBase: raise NotImplementedError - def permute(self, permutation: List[int]) -> 'OperatorBase': + def permute(self, permutation: List[int]) -> OperatorBase: raise NotImplementedError def exp_i(self) -> OperatorBase: diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index cfd8e6dc6b..d848bbd82e 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -145,7 +145,7 @@ def adjoint(self) -> OperatorBase: def _expand_dim(self, num_qubits: int) -> 'StateFn': raise NotImplementedError - def permute(self, permutation: List[int]) -> 'OperatorBase': + def permute(self, permutation: List[int]) -> OperatorBase: r""" Permute the qubits of the state function. diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 317745d813..05be6a278c 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -107,7 +107,7 @@ def permute(self, permutation: List[int]) -> 'VectorStateFn': coeff=self.coeff, is_measurement=self.is_measurement) - def to_dict_fn(self) -> 'StateFn': + def to_dict_fn(self) -> StateFn: r""" Creates the equivalent state function of type DictStateFn. From 6fb010c4c76e61db233732aad53cacc5e87713a7 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 13 Aug 2020 09:04:11 +0200 Subject: [PATCH 60/91] fix mypy --- qiskit/aqua/utils/arithmetic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index 09be39814b..c5d1540661 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -16,8 +16,8 @@ Arithmetic Utilities """ +from typing import List, Tuple import numpy as np -from typing import List def normalize_vector(vector): @@ -98,7 +98,7 @@ def next_power_of_2_base(n): return base -def transpositions(permutation: List[int]): +def transpositions(permutation: List[int]) -> List[Tuple[int, int]]: """Return a sequence of transpositions, corresponding to the permutation. Args: From 3905c4773e5a684bec8d2f6f5361d2bd929f847e Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 13 Aug 2020 18:23:30 +0200 Subject: [PATCH 61/91] fixed mypy --- qiskit/aqua/utils/arithmetic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index c5d1540661..3e150b4449 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -107,7 +107,7 @@ def transpositions(permutation: List[int]) -> List[Tuple[int, int]]: Returns: List of transpositions, corresponding to the permutation. For permutation = [3, 0, 2, 1], - returns [ (0,1), (0,3) ] + returns [(0,1), (0,3)] """ unchecked = [True] * len(permutation) cyclic_form = [] @@ -132,4 +132,4 @@ def transpositions(permutation: List[int]) -> List[Tuple[int, int]]: first = x[0] for y in x[len_x - 1:0:-1]: res.append((first, y)) - return res + return res # type: ignore From 90679bb9dc62797dc62019a26563274d6183633b Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 13 Aug 2020 19:32:09 +0200 Subject: [PATCH 62/91] removed unused import --- qiskit/aqua/operators/evolutions/evolved_op.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 5385989ff6..7fc8201b42 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -24,7 +24,6 @@ from ..operator_base import OperatorBase from ..primitive_ops.primitive_op import PrimitiveOp from ..primitive_ops.matrix_op import MatrixOp -from ..primitive_ops.pauli_op import PauliOp # pylint: disable=cyclic-import from ..list_ops import ListOp from ..list_ops.summed_op import SummedOp from ..list_ops.composed_op import ComposedOp From 88b782afad2e52787ef220bd6af6f97276c0b5e1 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 21:32:54 +0200 Subject: [PATCH 63/91] Update qiskit/aqua/operators/evolutions/evolved_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/evolutions/evolved_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 7fc8201b42..ce9d758461 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -96,7 +96,7 @@ def permute(self, permutation: List[int]) -> OperatorBase: return EvolvedOp(self.primitive.permute(permutation), coeff=self.coeff) # type: ignore def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) From 780099f0f1b994f3ff567989b1e300bc212b5a86 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 21:33:13 +0200 Subject: [PATCH 64/91] Update qiskit/aqua/operators/list_ops/composed_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/list_ops/composed_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 2bdd2c6d9c..d79dd8b050 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -66,7 +66,7 @@ def adjoint(self) -> OperatorBase: return ComposedOp([op.adjoint() for op in reversed(self.oplist)], coeff=self.coeff) def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) From 8ad7ed37b039f496503efc847d4c48acd4ffa975 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 21:40:48 +0200 Subject: [PATCH 65/91] Update qiskit/aqua/operators/state_fns/state_fn.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/state_fns/state_fn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index d848bbd82e..2b4eca779c 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -146,8 +146,7 @@ def _expand_dim(self, num_qubits: int) -> 'StateFn': raise NotImplementedError def permute(self, permutation: List[int]) -> OperatorBase: - r""" - Permute the qubits of the state function. + """Permute the qubits of the state function. Args: permutation: A list defining where each qubit should be permuted. The qubit at index From 6b7ec70f4ca148d339a1bcdc9f7b715c24fd1be1 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 21:44:00 +0200 Subject: [PATCH 66/91] Update qiskit/aqua/operators/state_fns/state_fn.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index 2b4eca779c..d4cc7e7bac 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -206,7 +206,7 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def _expand_shorter_operator_and_permute(self, other: OperatorBase, - permutation: List[int] = None) \ + permutation: Optional[List[int]] = None) \ -> Tuple[OperatorBase, OperatorBase]: from qiskit.aqua.operators import Zero From f47bf4a4bd6ded39f7598552304b139717073966 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 21:44:10 +0200 Subject: [PATCH 67/91] Update qiskit/aqua/operators/state_fns/vector_state_fn.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/state_fns/vector_state_fn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 05be6a278c..f491f3d5ad 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -108,8 +108,7 @@ def permute(self, permutation: List[int]) -> 'VectorStateFn': is_measurement=self.is_measurement) def to_dict_fn(self) -> StateFn: - r""" - Creates the equivalent state function of type DictStateFn. + """Creates the equivalent state function of type DictStateFn. Returns: A new DictStateFn equivalent to ``self``. From f302b033cfaee7e91b26fc3007d8fa2c3bed866f Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 21:45:26 +0200 Subject: [PATCH 68/91] Update qiskit/aqua/operators/list_ops/list_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/list_ops/list_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index c853b73273..90cf947516 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -244,7 +244,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc) # type: ignore def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) From da22d2330b1332d8d8f4d93e9682a2ef5baf3318 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:17:14 +0200 Subject: [PATCH 69/91] Update qiskit/aqua/operators/list_ops/tensored_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/list_ops/tensored_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 9e622feaeb..01df096ecc 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -55,7 +55,7 @@ def distributive(self) -> bool: return False def _expand_dim(self, num_qubits: int) -> 'TensoredOp': - """ Appends I ^ num_qubits to ``oplist``. Choice of PauliOp as + """Appends I ^ num_qubits to ``oplist``. Choice of PauliOp as identity is arbitrary and can be substituted for other PrimitiveOp identity. Returns: From a6beffaac680cd60b3616c083c2b53890dbe5b27 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:19:16 +0200 Subject: [PATCH 70/91] Update qiskit/aqua/operators/operator_base.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/operator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 24d99d4a1c..c10a569e13 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -444,7 +444,7 @@ def assign_parameters(self, @abstractmethod def _expand_dim(self, num_qubits: int) -> 'OperatorBase': - r""" Expands the operator with identity operator of dimension 2**num_qubits. + """Expands the operator with identity operator of dimension 2**num_qubits. Returns: Operator corresponding to self.tensor(identity_operator), where dimension of identity From 3504657ff18d79c25f2f9a294b93572d1e464e0b Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:19:43 +0200 Subject: [PATCH 71/91] Update qiskit/aqua/operators/operator_base.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/operator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index c10a569e13..673df07b09 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -454,7 +454,7 @@ def _expand_dim(self, num_qubits: int) -> 'OperatorBase': @abstractmethod def permute(self, permutation: List[int]) -> 'OperatorBase': - r""" Permutes the qubits of the operator. + """Permutes the qubits of the operator. Args: permutation: A list defining where each qubit should be permuted. The qubit at index From 667fe456cea90f59a0d565fc5ab17767731df62b Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:23:20 +0200 Subject: [PATCH 72/91] Update qiskit/aqua/operators/operator_base.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/operator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 673df07b09..16b6649ea1 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -551,7 +551,7 @@ def __matmul__(self, other: 'OperatorBase') -> 'OperatorBase': @abstractmethod def compose(self, other: 'OperatorBase', - permutation: List[int] = None, front: bool = False) -> '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 ``@``. From 794ea4de97e9713cdcea9dd3f2ba19f993df2a60 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:24:02 +0200 Subject: [PATCH 73/91] Update qiskit/aqua/operators/primitive_ops/circuit_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/primitive_ops/circuit_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 290e4cefd3..c2f50a916b 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -110,7 +110,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) From 628b500036678273991eebfe410ecbcf284b33d2 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:36:33 +0200 Subject: [PATCH 74/91] Update qiskit/aqua/operators/primitive_ops/matrix_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 64a3995f61..bb23572b48 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -122,7 +122,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Operator[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) From c48818753cf6741d636b6ce1862d0e0037a7e326 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Wed, 19 Aug 2020 22:37:28 +0200 Subject: [PATCH 75/91] Update qiskit/aqua/operators/primitive_ops/matrix_op.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index bb23572b48..33e5a0ac82 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -134,7 +134,7 @@ def compose(self, other: OperatorBase, return super(MatrixOp, self).compose(other) - def permute(self, permutation: List[int] = None) -> 'MatrixOp': + def permute(self, permutation: Operator[List[int]] = None) -> 'MatrixOp': """Creates a new MatrixOp that acts on the permuted qubits. Args: From b3560b13b86cc74bf3ad5b5f3fb45ff1dc851dc8 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Wed, 19 Aug 2020 22:41:33 +0200 Subject: [PATCH 76/91] style fixed --- qiskit/aqua/operators/evolutions/evolved_op.py | 7 +++---- qiskit/aqua/operators/list_ops/tensored_op.py | 4 ++-- qiskit/aqua/operators/operator_base.py | 1 - 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 7fc8201b42..e4aa5ca4cc 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -98,12 +98,11 @@ def permute(self, permutation: List[int]) -> OperatorBase: def compose(self, other: OperatorBase, permutation: List[int] = None, front: bool = False) -> OperatorBase: - self, other = self._expand_shorter_operator_and_permute(other, # type: ignore - permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) if front: - return other.compose(self) + return other.compose(new_self) if isinstance(other, ComposedOp): - return ComposedOp([self] + other.oplist) # type: ignore + return ComposedOp([new_self] + other.oplist) # type: ignore return ComposedOp([self, other]) diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index 9e622feaeb..5431748ae9 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -61,8 +61,8 @@ def _expand_dim(self, num_qubits: int) -> 'TensoredOp': Returns: TensoredOp expanded with identity operator. """ - from qiskit.aqua.operators import PauliOp - return TensoredOp(self.oplist + [PauliOp(Pauli(label='I' * num_qubits))], coeff=self.coeff) + 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): diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 24d99d4a1c..69827f1045 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -532,7 +532,6 @@ def _expand_shorter_operator_and_permute(self, other: 'OperatorBase', elif other.num_qubits < self.num_qubits: other = other._expand_dim(self.num_qubits - other.num_qubits) elif other.num_qubits > self.num_qubits: - # type: ignore new_self = self._expand_dim(other.num_qubits - self.num_qubits) return new_self, other From e15691445e3259758958ba8b70c8084acd5cfc63 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 20 Aug 2020 08:27:18 +0200 Subject: [PATCH 77/91] fixed styles --- qiskit/aqua/operators/list_ops/composed_op.py | 2 +- qiskit/aqua/operators/list_ops/tensored_op.py | 1 - qiskit/aqua/operators/primitive_ops/matrix_op.py | 4 ++-- qiskit/aqua/operators/primitive_ops/pauli_op.py | 6 +++--- qiskit/aqua/operators/primitive_ops/primitive_op.py | 2 +- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 4 ++-- qiskit/aqua/operators/state_fns/state_fn.py | 2 +- qiskit/aqua/utils/arithmetic.py | 4 ++-- 8 files changed, 12 insertions(+), 13 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index d79dd8b050..a1050099d1 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -14,7 +14,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 diff --git a/qiskit/aqua/operators/list_ops/tensored_op.py b/qiskit/aqua/operators/list_ops/tensored_op.py index e719a872d0..939b480d92 100644 --- a/qiskit/aqua/operators/list_ops/tensored_op.py +++ b/qiskit/aqua/operators/list_ops/tensored_op.py @@ -19,7 +19,6 @@ import numpy as np from qiskit.circuit import ParameterExpression -from qiskit.quantum_info import Pauli from ..operator_base import OperatorBase from .list_op import ListOp diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 33e5a0ac82..3471dbadcb 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -122,7 +122,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) def compose(self, other: OperatorBase, - permutation: Operator[List[int]] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) @@ -134,7 +134,7 @@ def compose(self, other: OperatorBase, return super(MatrixOp, self).compose(other) - def permute(self, permutation: Operator[List[int]] = None) -> 'MatrixOp': + def permute(self, permutation: Optional[List[int]] = None) -> 'MatrixOp': """Creates a new MatrixOp that acts on the permuted qubits. Args: diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index e799b9081b..c201bc5780 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -14,7 +14,7 @@ """ PauliOp Class """ -from typing import Union, Set, Dict, cast, List +from typing import Union, Set, Dict, cast, List, Optional import logging import numpy as np from scipy.sparse import spmatrix @@ -101,7 +101,7 @@ def tensor(self, other: OperatorBase) -> OperatorBase: return TensoredOp([self, other]) - def permute(self, permutation: List[int] = None) -> 'PauliOp': + def permute(self, permutation: List[int]) -> 'PauliOp': """Permutes the sequence of Pauli matrices. Args: @@ -125,7 +125,7 @@ def permute(self, permutation: List[int] = None) -> 'PauliOp': return PauliOp(Pauli(label=''.join(new_pauli_list)), self.coeff) def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: self, other = self._expand_shorter_operator_and_permute(other, # type: ignore permutation) diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index 619c29bf37..c71b58275f 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -156,7 +156,7 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: from ..list_ops.composed_op import ComposedOp if isinstance(other, ComposedOp): comp_with_first = self.compose(other.oplist[0]) diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index ba4542cb71..4381598408 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -15,7 +15,7 @@ """ CircuitStateFn Class """ -from typing import Union, Set, List, cast +from typing import Union, Set, List, cast, Optional import numpy as np from qiskit import QuantumCircuit, BasicAer, execute, ClassicalRegister @@ -140,7 +140,7 @@ def adjoint(self) -> OperatorBase: is_measurement=(not self.is_measurement)) def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: if not self.is_measurement and not front: raise ValueError( 'Composition with a Statefunctions in the first operand is not defined.') diff --git a/qiskit/aqua/operators/state_fns/state_fn.py b/qiskit/aqua/operators/state_fns/state_fn.py index d4cc7e7bac..6190f375b2 100644 --- a/qiskit/aqua/operators/state_fns/state_fn.py +++ b/qiskit/aqua/operators/state_fns/state_fn.py @@ -240,7 +240,7 @@ def to_density_matrix(self, massive: bool = False) -> np.ndarray: raise NotImplementedError def compose(self, other: OperatorBase, - permutation: List[int] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: r""" Composition (Linear algebra-style: A@B(x) = A(B(x))) is not well defined for states in the binary function model, but is well defined for measurements. diff --git a/qiskit/aqua/utils/arithmetic.py b/qiskit/aqua/utils/arithmetic.py index 3e150b4449..110b004f75 100644 --- a/qiskit/aqua/utils/arithmetic.py +++ b/qiskit/aqua/utils/arithmetic.py @@ -127,9 +127,9 @@ def transpositions(permutation: List[int]) -> List[Tuple[int, int]]: for x in cyclic_form: len_x = len(x) if len_x == 2: - res.append(tuple(x)) + res.append((x[0], x[1])) elif len_x > 2: first = x[0] for y in x[len_x - 1:0:-1]: res.append((first, y)) - return res # type: ignore + return res From ad21d72162ee0aa24ffe95d493330cfe05e84cdd Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 20 Aug 2020 23:32:12 +0200 Subject: [PATCH 78/91] fixed import after merge --- test/aqua/operators/test_op_construction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index ff13841748..54ec1fd01b 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -27,7 +27,7 @@ from qiskit.circuit.library import CZGate, ZGate from qiskit.aqua.operators import ( - X, Y, Z, I, CX, T, H, Minus, PrimitiveOp, PauliOp, CircuitOp, MatrixOp, EvolvedOp, + X, Y, Z, I, CX, T, H, Minus, PrimitiveOp, PauliOp, CircuitOp, MatrixOp, EvolvedOp, StateFn, CircuitStateFn, VectorStateFn, DictStateFn, OperatorStateFn, ListOp, ComposedOp, TensoredOp, SummedOp ) From f70f48fe11b81dfb1953b574f764476478aee9b6 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Thu, 20 Aug 2020 23:43:31 +0200 Subject: [PATCH 79/91] Update qiskit/aqua/operators/state_fns/dict_state_fn.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/state_fns/dict_state_fn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 8b363d4373..e1781ca5ef 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -131,8 +131,7 @@ def _expand_dim(self, num_qubits: int) -> 'DictStateFn': return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) def to_vector_state_fn(self) -> 'VectorStateFn': # type: ignore - r""" - Creates the equivalent state function of type VectorStateFn. + """Creates the equivalent state function of type VectorStateFn. Returns: A new VectorStateFn equivalent to ``self``. From 6ba866bdcbdeead35915034a4882571850ed466c Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 20 Aug 2020 23:55:32 +0200 Subject: [PATCH 80/91] removed duplicate method to_vector_state_fn (to_matrix_op was already defined) --- qiskit/aqua/operators/state_fns/dict_state_fn.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/dict_state_fn.py b/qiskit/aqua/operators/state_fns/dict_state_fn.py index 8b363d4373..f2b2e824cc 100644 --- a/qiskit/aqua/operators/state_fns/dict_state_fn.py +++ b/qiskit/aqua/operators/state_fns/dict_state_fn.py @@ -130,19 +130,6 @@ def _expand_dim(self, num_qubits: int) -> 'DictStateFn': new_dict = {key + pad: value for key, value in self.primitive.items()} return DictStateFn(new_dict, coeff=self.coeff, is_measurement=self.is_measurement) - def to_vector_state_fn(self) -> 'VectorStateFn': # type: ignore - r""" - Creates the equivalent state function of type VectorStateFn. - - Returns: - A new VectorStateFn equivalent to ``self``. - """ - states = int(2 ** self.num_qubits) - probs = np.zeros(states) + 0.j - for k, v in self.primitive.items(): - probs[int(k, 2)] = v - return VectorStateFn(probs, coeff=self.coeff, is_measurement=self.is_measurement) - def tensor(self, other: OperatorBase) -> OperatorBase: # Both dicts if isinstance(other, DictStateFn): From d9119331e24ac120f28d12b306c70aa353848df2 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Fri, 21 Aug 2020 00:37:58 +0200 Subject: [PATCH 81/91] new_self instead of self in EvolvedOp --- qiskit/aqua/operators/evolutions/evolved_op.py | 2 +- test/aqua/operators/test_op_construction.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index 6bf1b0455f..681aebc63f 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -104,7 +104,7 @@ def compose(self, other: OperatorBase, if isinstance(other, ComposedOp): return ComposedOp([new_self] + other.oplist) # type: ignore - return ComposedOp([self, other]) + return ComposedOp([new_self, other]) def __str__(self) -> str: prim_str = str(self.primitive) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 54ec1fd01b..c7fa84819e 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -584,6 +584,9 @@ def test_compose_with_indices(self): composed_primitive_op = \ evolved_op @ pauli_op.compose(circuit_op, permutation=indices, front=True) @ matrix_op + mat1 = permuted_primitive_op.to_matrix() + mat2 = composed_primitive_op.to_matrix() + self.assertTrue(np.allclose(permuted_primitive_op.to_matrix(), composed_primitive_op.to_matrix())) self.assertEqual(num_qubits, permuted_primitive_op.num_qubits) From 9def93c8bf59efecafc808d9ab71cca0c0632c74 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Fri, 21 Aug 2020 00:41:08 +0200 Subject: [PATCH 82/91] test_op_construction refactored --- test/aqua/operators/test_op_construction.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index c7fa84819e..54ec1fd01b 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -584,9 +584,6 @@ def test_compose_with_indices(self): composed_primitive_op = \ evolved_op @ pauli_op.compose(circuit_op, permutation=indices, front=True) @ matrix_op - mat1 = permuted_primitive_op.to_matrix() - mat2 = composed_primitive_op.to_matrix() - self.assertTrue(np.allclose(permuted_primitive_op.to_matrix(), composed_primitive_op.to_matrix())) self.assertEqual(num_qubits, permuted_primitive_op.num_qubits) From bb826d54f1e9e7de3d114b66f704235970bb10aa Mon Sep 17 00:00:00 2001 From: molar-volume Date: Sun, 23 Aug 2020 00:36:06 +0200 Subject: [PATCH 83/91] fix after merge --- qiskit/aqua/operators/state_fns/vector_state_fn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index f491f3d5ad..e29ac6db9a 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -23,7 +23,6 @@ from qiskit.circuit import ParameterExpression from qiskit.aqua import aqua_globals -from .. import CircuitOp from ..operator_base import OperatorBase from .state_fn import StateFn from ..list_ops.list_op import ListOp @@ -101,6 +100,7 @@ def permute(self, permutation: List[int]) -> 'VectorStateFn': transpositions = arithmetic.transpositions(permutation) for trans in transpositions: qc.swap(trans[0], trans[1]) + from .. import CircuitOp matrix = CircuitOp(qc).to_matrix() vector = new_self.primitive.data return VectorStateFn(primitive=matrix.dot(vector), From ac5f12262db8d3c79c5807efeee700a09294a4f1 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Thu, 3 Sep 2020 10:21:57 +0200 Subject: [PATCH 84/91] Update qiskit/aqua/operators/operator_base.py Co-authored-by: Julien Gacon --- qiskit/aqua/operators/operator_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/operator_base.py b/qiskit/aqua/operators/operator_base.py index 24b7d92a90..2571c15a92 100644 --- a/qiskit/aqua/operators/operator_base.py +++ b/qiskit/aqua/operators/operator_base.py @@ -528,7 +528,7 @@ def _get_param_dict_for_index(unrolled_dict: Dict[ParameterExpression, List[Numb return {k: v[i] for (k, v) in unrolled_dict.items()} def _expand_shorter_operator_and_permute(self, other: 'OperatorBase', - permutation: List[int] = None) \ + permutation: Optional[List[int]] = None) \ -> Tuple['OperatorBase', 'OperatorBase']: if permutation is not None: other = other.permute(permutation) From ebdba411eadd94457e1729f25b290c9c3abb7ebc Mon Sep 17 00:00:00 2001 From: Julien Gacon Date: Thu, 3 Sep 2020 10:50:40 +0200 Subject: [PATCH 85/91] Typo: List -> Listt --- qiskit/aqua/operators/state_fns/vector_state_fn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/state_fns/vector_state_fn.py b/qiskit/aqua/operators/state_fns/vector_state_fn.py index 4de3772768..134900b0b0 100644 --- a/qiskit/aqua/operators/state_fns/vector_state_fn.py +++ b/qiskit/aqua/operators/state_fns/vector_state_fn.py @@ -13,7 +13,7 @@ """ VectorStateFn Class """ -from typing import Union, Set, Optional, Dict, Listt +from typing import Union, Set, Optional, Dict, List import numpy as np from qiskit import QuantumCircuit From e87add5be0760993a734ce0e9b3ad3e179577601 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Thu, 17 Sep 2020 18:45:06 +0200 Subject: [PATCH 86/91] raise AquaError in ListOp.permute, if ListOp contains operators with different num_qubit --- qiskit/aqua/operators/list_ops/list_op.py | 8 ++++++-- test/aqua/operators/test_op_construction.py | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index aef98b93bd..0f88f563db 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -235,8 +235,12 @@ def permute(self, permutation: List[int]) -> 'ListOp': new_self = self circuit_size = max(permutation) + 1 - if self.num_qubits != len(permutation): - raise AquaError("New index must be defined for each qubit of the operator.") + 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.") if self.num_qubits < circuit_size: # pad the operator with identities new_self = self._expand_dim(circuit_size - self.num_qubits) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 96453a3477..65007a4741 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -801,6 +801,11 @@ def test_op_to_circuit_with_parameters(self): summed_op_with_param = op1_with_param + op2_with_param # unitary self.assertRaises(AquaError, summed_op_with_param.to_circuit) # should raise Aqua error + def test_permute_list_op_with_inconsistent_num_qubits(self): + """Test if permute raises error if ListOp contains operators with different num_qubits.""" + list_op = ListOp([X, X ^ X]) + self.assertRaises(list_op.permute([0, 1]), AquaError) + @data(Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, -1]])) def test_op_hashing(self, op): """Regression test against faulty set comparison. From 8cb9ccf4fac739141a7803fad1ac6031f5978f29 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Sat, 19 Sep 2020 10:16:49 +0200 Subject: [PATCH 87/91] self renamed to new_self in compose methods --- .../aqua/operators/evolutions/evolved_op.py | 2 +- qiskit/aqua/operators/list_ops/composed_op.py | 19 ++++++++++--------- qiskit/aqua/operators/list_ops/list_op.py | 13 +++++++------ .../operators/primitive_ops/circuit_op.py | 19 ++++++++++--------- .../aqua/operators/primitive_ops/matrix_op.py | 15 ++++++++------- .../aqua/operators/primitive_ops/pauli_op.py | 19 ++++++++++--------- .../operators/primitive_ops/primitive_op.py | 10 ++++++---- test/aqua/operators/test_op_construction.py | 3 ++- 8 files changed, 54 insertions(+), 46 deletions(-) diff --git a/qiskit/aqua/operators/evolutions/evolved_op.py b/qiskit/aqua/operators/evolutions/evolved_op.py index c9908837ea..e6fe009918 100644 --- a/qiskit/aqua/operators/evolutions/evolved_op.py +++ b/qiskit/aqua/operators/evolutions/evolved_op.py @@ -100,7 +100,7 @@ def compose(self, other: OperatorBase, if front: return other.compose(new_self) if isinstance(other, ComposedOp): - return ComposedOp([new_self] + other.oplist) # type: ignore + return ComposedOp([new_self] + other.oplist) return ComposedOp([new_self, other]) diff --git a/qiskit/aqua/operators/list_ops/composed_op.py b/qiskit/aqua/operators/list_ops/composed_op.py index 67ebd81b3b..fb6419c01a 100644 --- a/qiskit/aqua/operators/list_ops/composed_op.py +++ b/qiskit/aqua/operators/list_ops/composed_op.py @@ -85,27 +85,28 @@ def adjoint(self) -> OperatorBase: def compose(self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: - self, other = self._expand_shorter_operator_and_permute(other, # type: ignore - permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) + new_self = cast(ComposedOp, new_self) + if front: - return other.compose(self) + 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, diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 0f88f563db..07ff7c12c8 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -13,7 +13,7 @@ """ 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 @@ -240,7 +240,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': 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.") + "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) @@ -261,14 +261,15 @@ def permute(self, permutation: List[int]) -> 'ListOp': def compose(self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: - self, other = self._expand_shorter_operator_and_permute(other, # type: ignore - permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) + new_self = cast(ListOp, new_self) + if front: - return other.compose(self) + 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: diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index 48d5e277e1..e770fad2ce 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -111,10 +111,11 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: - self, other = self._expand_shorter_operator_and_permute(other, # type: ignore - permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) + # new_self = cast(CircuitOp, new_self) + if front: - return other.compose(self) + return other.compose(new_self) # ignore # pylint: disable=cyclic-import,import-outside-toplevel from ..operator_globals import Zero @@ -122,22 +123,22 @@ def compose(self, other: OperatorBase, 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().compose(other, permutation) def to_matrix(self, massive: bool = False) -> np.ndarray: if self.num_qubits > 16 and not massive: diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 7cf3786d2c..79d5e4b8ff 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -12,7 +12,7 @@ """ MatrixOp Class """ -from typing import Union, Optional, Set, Dict, List +from typing import Union, Optional, Set, Dict, List, cast import logging import numpy as np from scipy.sparse import spmatrix @@ -122,15 +122,16 @@ def tensor(self, other: OperatorBase) -> OperatorBase: def compose(self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: - self, other = self._expand_shorter_operator_and_permute(other, # type: ignore - permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) + # new_self = cast(MatrixOp, new_self) + if front: - return other.compose(self) + return other.compose(new_self) if isinstance(other, MatrixOp): - return MatrixOp(self.primitive.compose(other.primitive, front=True), # type: ignore - coeff=self.coeff * other.coeff) + return MatrixOp(new_self.primitive.compose(other.primitive, front=True), # type: ignore + coeff=new_self.coeff * other.coeff) - return super().compose(other) + return super().compose(other, permutation) def permute(self, permutation: Optional[List[int]] = None) -> 'MatrixOp': """Creates a new MatrixOp that acts on the permuted qubits. diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index c4606b5c7b..bb885b4f3a 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -125,26 +125,27 @@ def permute(self, permutation: List[int]) -> 'PauliOp': def compose(self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: - self, other = self._expand_shorter_operator_and_permute(other, # type: ignore - permutation) + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) + # new_self = cast(PauliOp, new_self) + if front: - return other.compose(self) + return other.compose(new_self) # If self is identity, just return other. - if not any(self.primitive.x + self.primitive.z): # type: ignore - return other * self.coeff # type: ignore + if not any(new_self.primitive.x + new_self.primitive.z): # type: ignore + return other * new_self.coeff # type: ignore # Both Paulis if isinstance(other, PauliOp): - product, phase = Pauli.sgn_prod(self.primitive, other.primitive) - return PrimitiveOp(product, coeff=self.coeff * other.coeff * phase) + product, phase = Pauli.sgn_prod(new_self.primitive, other.primitive) + return PrimitiveOp(product, coeff=new_self.coeff * other.coeff * phase) # pylint: disable=cyclic-import,import-outside-toplevel from .circuit_op import CircuitOp from ..state_fns.circuit_state_fn import CircuitStateFn if isinstance(other, (CircuitOp, CircuitStateFn)): - return self.to_circuit_op().compose(other) + return new_self.to_circuit_op().compose(other) - return super().compose(other) + return super().compose(other, permutation) def to_matrix(self, massive: bool = False) -> np.ndarray: if self.num_qubits > 16 and not massive: diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index abec6ab08d..62adbb7a91 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -154,16 +154,18 @@ def tensorpower(self, other: int) -> Union[OperatorBase, int]: return temp def compose(self, other: OperatorBase, - permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: + permutation: Optional[List[int]] = None, front: bool = False) -> \ + OperatorBase: from ..list_ops.composed_op import ComposedOp + new_self, other = self._expand_shorter_operator_and_permute(other, permutation) if isinstance(other, ComposedOp): - comp_with_first = self.compose(other.oplist[0]) + comp_with_first = new_self.compose(other.oplist[0]) if not isinstance(comp_with_first, ComposedOp): new_oplist = [comp_with_first] + other.oplist[1:] return ComposedOp(new_oplist, coeff=other.coeff) - return ComposedOp([self] + other.oplist, coeff=other.coeff) # type: ignore + return ComposedOp([new_self] + other.oplist, coeff=other.coeff) # type: ignore - return ComposedOp([self, other]) + return ComposedOp([new_self, other]) def power(self, exponent: int) -> OperatorBase: if not isinstance(exponent, int) or exponent <= 0: diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 65007a4741..ee2ec09c28 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -804,7 +804,8 @@ def test_op_to_circuit_with_parameters(self): def test_permute_list_op_with_inconsistent_num_qubits(self): """Test if permute raises error if ListOp contains operators with different num_qubits.""" list_op = ListOp([X, X ^ X]) - self.assertRaises(list_op.permute([0, 1]), AquaError) + # self.assertRaises(ValueError, list_op.permute([0, 1])) + self.assertRaises(AquaError, list_op.permute, [0, 1]) @data(Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, -1]])) def test_op_hashing(self, op): From 341f4897c6a61d3be0120e825bf4eaa4d4fff8ec Mon Sep 17 00:00:00 2001 From: molar-volume Date: Sat, 19 Sep 2020 16:07:52 +0200 Subject: [PATCH 88/91] fix linting --- qiskit/aqua/operators/primitive_ops/circuit_op.py | 2 +- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index e770fad2ce..e47c373fcb 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -112,7 +112,7 @@ 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) + new_self = cast(CircuitOp, new_self) if front: return other.compose(new_self) diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index 79d5e4b8ff..ac9c8be528 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -123,7 +123,7 @@ 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(MatrixOp, new_self) + new_self = cast(MatrixOp, new_self) if front: return other.compose(new_self) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index bb885b4f3a..dc87455787 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -126,7 +126,7 @@ 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(PauliOp, new_self) + new_self = cast(PauliOp, new_self) if front: return other.compose(new_self) From 9faa2cb44f3d7daf0667d910b646c695e9b7ed48 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Sun, 20 Sep 2020 10:01:43 +0200 Subject: [PATCH 89/91] unnecessary comment removed --- test/aqua/operators/test_op_construction.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index ee2ec09c28..90a6ee5541 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -804,7 +804,6 @@ def test_op_to_circuit_with_parameters(self): def test_permute_list_op_with_inconsistent_num_qubits(self): """Test if permute raises error if ListOp contains operators with different num_qubits.""" list_op = ListOp([X, X ^ X]) - # self.assertRaises(ValueError, list_op.permute([0, 1])) self.assertRaises(AquaError, list_op.permute, [0, 1]) @data(Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, -1]])) From 46a49cbbae6ae0377e00ef33bd0658da5d9a3fb5 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Sun, 20 Sep 2020 12:01:34 +0200 Subject: [PATCH 90/91] remove type ignore --- qiskit/aqua/operators/list_ops/list_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/list_ops/list_op.py b/qiskit/aqua/operators/list_ops/list_op.py index 07ff7c12c8..370d887f3e 100644 --- a/qiskit/aqua/operators/list_ops/list_op.py +++ b/qiskit/aqua/operators/list_ops/list_op.py @@ -256,7 +256,7 @@ def permute(self, permutation: List[int]) -> 'ListOp': from qiskit.aqua.operators import CircuitOp - return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc) # type: ignore + return CircuitOp(qc.reverse_ops()) @ new_self @ CircuitOp(qc) def compose(self, other: OperatorBase, permutation: Optional[List[int]] = None, front: bool = False) -> OperatorBase: From 8e726d09133acf883bde5db5e73063d7ea0018e0 Mon Sep 17 00:00:00 2001 From: molar-volume Date: Sun, 20 Sep 2020 21:58:31 +0200 Subject: [PATCH 91/91] avoid unnecessary permutation --- qiskit/aqua/operators/primitive_ops/circuit_op.py | 2 +- qiskit/aqua/operators/primitive_ops/matrix_op.py | 2 +- qiskit/aqua/operators/primitive_ops/pauli_op.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index e47c373fcb..5e600d6ce4 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -138,7 +138,7 @@ def compose(self, other: OperatorBase, else: return CircuitOp(new_qc, coeff=new_self.coeff * other.coeff) - return super().compose(other, permutation) + return super(CircuitOp, new_self).compose(other) def to_matrix(self, massive: bool = False) -> np.ndarray: if self.num_qubits > 16 and not massive: diff --git a/qiskit/aqua/operators/primitive_ops/matrix_op.py b/qiskit/aqua/operators/primitive_ops/matrix_op.py index ac9c8be528..ec91a450cd 100644 --- a/qiskit/aqua/operators/primitive_ops/matrix_op.py +++ b/qiskit/aqua/operators/primitive_ops/matrix_op.py @@ -131,7 +131,7 @@ def compose(self, other: OperatorBase, return MatrixOp(new_self.primitive.compose(other.primitive, front=True), # type: ignore coeff=new_self.coeff * other.coeff) - return super().compose(other, permutation) + return super(MatrixOp, new_self).compose(other) def permute(self, permutation: Optional[List[int]] = None) -> 'MatrixOp': """Creates a new MatrixOp that acts on the permuted qubits. diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index dc87455787..7e4adf7af6 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -145,7 +145,7 @@ def compose(self, other: OperatorBase, if isinstance(other, (CircuitOp, CircuitStateFn)): return new_self.to_circuit_op().compose(other) - return super().compose(other, permutation) + return super(PauliOp, new_self).compose(other) def to_matrix(self, massive: bool = False) -> np.ndarray: if self.num_qubits > 16 and not massive: