From f58bee59cbac78cd9be0bb30123cbf5428558840 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Wed, 17 Jun 2020 15:00:00 +0200 Subject: [PATCH 01/27] simplify and reduce, add equals to SummedOp, update tests --- qiskit/aqua/operators/list_ops/summed_op.py | 54 +++++++++++++++++++ .../converters/ising_to_quadratic_program.py | 30 +++++++---- .../converters/quadratic_program_to_ising.py | 8 +-- test/aqua/operators/test_op_construction.py | 14 ++--- test/optimization/test_converters.py | 38 +++++++------ 5 files changed, 101 insertions(+), 43 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index d516a82368..de2b5760f5 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -116,8 +116,33 @@ def simplify(self) -> 'SummedOp': # Try collapsing list or trees of Sums. # TODO be smarter about the fact that any two ops in oplist could be evaluated for sum. def reduce(self) -> OperatorBase: + # first reduce constituents reduced_ops = [op.reduce() for op in self.oplist] reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff + + # then group duplicate operators + # e.g., ``SummedOp([2 * X ^ Y, X ^ Y]).simplify() -> SummedOp([3 * X ^ Y])``. + oplist = [] # type: List[OperatorBase] + coeffs = [] # type: List[Union[int, float, complex, ParameterExpression]] + for op in self.oplist: + if isinstance(op, PrimitiveOp): + new_op = PrimitiveOp(op.primitive) + new_coeff = op.coeff * self.coeff + if new_op in oplist: + index = oplist.index(new_op) + coeffs[index] += new_coeff + else: + oplist.append(new_op) + coeffs.append(new_coeff) + else: + if op in oplist: + index = oplist.index(op) + coeffs[index] += self.coeff + else: + oplist.append(op) + coeffs.append(self.coeff) + reduced_ops = SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore + if isinstance(reduced_ops, SummedOp) and len(reduced_ops.oplist) == 1: return reduced_ops.oplist[0] else: @@ -142,3 +167,32 @@ def to_legacy_op(self, massive: bool = False) -> LegacyBaseOperator: coeff = cast(float, self.coeff) return self.combo_fn(legacy_ops) * coeff + + def equals(self, other: OperatorBase) -> bool: + self_reduced, other_reduced = self.reduce(), other.reduce() + if not isinstance(other_reduced, type(self_reduced)): + return False + + # check if reduced op is still a SummedOp + if not isinstance(self_reduced, self.__class__): + return self_reduced == other_reduced + + if not len(self_reduced.oplist) == len(other_reduced.oplist): + return False + + # absorb coeffs into the operators + if self_reduced.coeff != 1: + self_reduced = SummedOp([op * self_reduced.coeff for op in self_reduced.oplist]) + if other_reduced.coeff != 1: + other_reduced = SummedOp([op * other_reduced.coeff for op in other_reduced.oplist]) + + # compare independent of order, for some reason set(...) == set(...) does not work + for op1 in self_reduced.oplist: + found = False + for op2 in other_reduced.oplist: + if op1 == op2: + found = True + break + if not found: + return False + return True diff --git a/qiskit/optimization/converters/ising_to_quadratic_program.py b/qiskit/optimization/converters/ising_to_quadratic_program.py index 3f56b96f75..7e6678add6 100644 --- a/qiskit/optimization/converters/ising_to_quadratic_program.py +++ b/qiskit/optimization/converters/ising_to_quadratic_program.py @@ -15,12 +15,12 @@ """The converter from a ```Operator``` to ``QuadraticProgram``.""" -from typing import Optional +from typing import Optional, Union import copy import numpy as np -from qiskit.aqua.operators.legacy import WeightedPauliOperator +from qiskit.aqua.operators import OperatorBase, WeightedPauliOperator, SummedOp from ..problems.quadratic_program import QuadraticProgram from ..exceptions import QiskitOptimizationError @@ -44,7 +44,8 @@ def __init__(self, linear: bool = False) -> None: self._qp = None # type: Optional[QuadraticProgram] self._linear = linear - def encode(self, qubit_op: WeightedPauliOperator, offset: float = 0.0) -> QuadraticProgram: + def encode(self, qubit_op: Union[OperatorBase, WeightedPauliOperator], offset: float = 0.0 + ) -> QuadraticProgram: """Convert a qubit operator and a shift value into a quadratic program Args: @@ -60,6 +61,8 @@ def encode(self, qubit_op: WeightedPauliOperator, offset: float = 0.0) -> Quadra QiskitOptimizationError: If there are more than 2 Pauli Zs in any Pauli term """ # Set properties + if isinstance(qubit_op, WeightedPauliOperator): + qubit_op = qubit_op.to_opflow() self._qubit_op = qubit_op self._offset = copy.deepcopy(offset) self._num_qubits = qubit_op.num_qubits @@ -134,24 +137,31 @@ def _create_qubo_matrix(self): # The other elements in the QUBO matrix is for quadratic terms of the qubit operator self._qubo_matrix = np.zeros((self._num_qubits, self._num_qubits)) - for pauli in self._qubit_op.paulis: + if not isinstance(self._qubit_op, SummedOp): + oplist = [self._qubit_op.to_pauli_op()] + else: + oplist = self._qubit_op.to_pauli_op().oplist + + for pauli_op in oplist: + pauli = pauli_op.primitive + coeff = pauli_op.coeff # Count the number of Pauli Zs in a Pauli term - lst_z = pauli[1].z.tolist() + lst_z = pauli.z.tolist() z_index = [i for i, z in enumerate(lst_z) if z is True] num_z = len(z_index) # Add its weight of the Pauli term to the corresponding element of QUBO matrix if num_z == 1: - self._qubo_matrix[z_index[0], z_index[0]] = pauli[0].real + self._qubo_matrix[z_index[0], z_index[0]] = coeff.real elif num_z == 2: - self._qubo_matrix[z_index[0], z_index[1]] = pauli[0].real + self._qubo_matrix[z_index[0], z_index[1]] = coeff.real else: raise QiskitOptimizationError( - 'There are more than 2 Pauli Zs in the Pauli term {}'.format(pauli[1].z) + 'There are more than 2 Pauli Zs in the Pauli term {}'.format(pauli.z) ) # If there are Pauli Xs in the Pauli term, raise an error - lst_x = pauli[1].x.tolist() + lst_x = pauli.x.tolist() x_index = [i for i, x in enumerate(lst_x) if x is True] if len(x_index) > 0: - raise QiskitOptimizationError('Pauli Xs exist in the Pauli {}'.format(pauli[1].x)) + raise QiskitOptimizationError('Pauli Xs exist in the Pauli {}'.format(pauli.x)) diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index d937bd6085..38098cd407 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -20,7 +20,7 @@ import numpy as np from qiskit.quantum_info import Pauli -from qiskit.aqua.operators import WeightedPauliOperator +from qiskit.aqua.operators import OperatorBase, PauliOp from ..problems.quadratic_program import QuadraticProgram from ..exceptions import QiskitOptimizationError @@ -33,7 +33,7 @@ def __init__(self) -> None: """Initialize the internal data structure.""" self._src = None # type: Optional[QuadraticProgram] - def encode(self, op: QuadraticProgram) -> Tuple[WeightedPauliOperator, float]: + def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: """Convert a problem into a qubit operator Args: @@ -114,6 +114,8 @@ def encode(self, op: QuadraticProgram) -> Tuple[WeightedPauliOperator, float]: shift += weight # Remove paulis whose coefficients are zeros. - qubit_op = WeightedPauliOperator(paulis=pauli_list) + qubit_op = sum(PauliOp(pauli, coeff=coeff) for coeff, pauli in pauli_list) + if len(pauli_list) > 0: # if the list is empty, qubit op is 0 + qubit_op = qubit_op.reduce() return qubit_op, shift diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 7583297fa7..4e2c5f2246 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -245,17 +245,11 @@ def test_summed_op(self): self.assertListEqual([op.coeff for op in sum_op], [2, 2]) sum_op = (X ^ X * 2) + (Y ^ Y) - sum_op += (Y ^ Y) + (X ^ X * 2) - with self.subTest('SummedOp test 3-a'): - self.assertEqual(sum_op.coeff, 1) - self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'YY', 'XX']) - self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1, 2]) - - sum_op = sum_op.simplify() - with self.subTest('SummedOp test 3-b'): - self.assertEqual(sum_op.coeff, 1) + sum_op += (Y ^ Y) + (X ^ X * 2) # if self == other the summed op directly multiplied by 2 + with self.subTest('SummedOp test 3'): + self.assertEqual(sum_op.coeff, 2) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) - self.assertListEqual([op.coeff for op in sum_op], [4, 2]) + self.assertListEqual([op.coeff for op in sum_op], [2, 1]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) with self.subTest('SummedOp test 4-a'): diff --git a/test/optimization/test_converters.py b/test/optimization/test_converters.py index aedcd19ee9..abe2efa3cd 100644 --- a/test/optimization/test_converters.py +++ b/test/optimization/test_converters.py @@ -20,7 +20,7 @@ import numpy as np from docplex.mp.model import Model -from qiskit.aqua.operators import WeightedPauliOperator +from qiskit.aqua.operators import Z, I from qiskit.aqua.algorithms import NumPyMinimumEigensolver from qiskit.optimization import QuadraticProgram, QiskitOptimizationError from qiskit.optimization.problems import Constraint, Variable @@ -34,25 +34,19 @@ ) from qiskit.optimization.algorithms import MinimumEigenOptimizer, CplexOptimizer, ADMMOptimizer from qiskit.optimization.algorithms.admm_optimizer import ADMMParameters -from qiskit.quantum_info import Pauli logger = logging.getLogger(__name__) - -QUBIT_OP_MAXIMIZE_SAMPLE = WeightedPauliOperator( - paulis=[ - [(-199999.5 + 0j), Pauli(z=[True, False, False, False], x=[False, False, False, False])], - [(-399999.5 + 0j), Pauli(z=[False, True, False, False], x=[False, False, False, False])], - [(-599999.5 + 0j), Pauli(z=[False, False, True, False], x=[False, False, False, False])], - [(-799999.5 + 0j), Pauli(z=[False, False, False, True], x=[False, False, False, False])], - [(100000 + 0j), Pauli(z=[True, True, False, False], x=[False, False, False, False])], - [(150000 + 0j), Pauli(z=[True, False, True, False], x=[False, False, False, False])], - [(300000 + 0j), Pauli(z=[False, True, True, False], x=[False, False, False, False])], - [(200000 + 0j), Pauli(z=[True, False, False, True], x=[False, False, False, False])], - [(400000 + 0j), Pauli(z=[False, True, False, True], x=[False, False, False, False])], - [(600000 + 0j), Pauli(z=[False, False, True, True], x=[False, False, False, False])], - ] -) +QUBIT_OP_MAXIMIZE_SAMPLE = (-199999.5 + 0j) * (I ^ I ^ I ^ Z) + \ + (-399999.5 + 0j) * (I ^ I ^ Z ^ I) + \ + (-599999.5 + 0j) * (I ^ Z ^ I ^ I) + \ + (-799999.5 + 0j) * (Z ^ I ^ I ^ I) + \ + (100000 + 0j) * (I ^ I ^ Z ^ Z) + \ + (150000 + 0j) * (I ^ Z ^ I ^ Z) + \ + (300000 + 0j) * (I ^ Z ^ Z ^ I) + \ + (200000 + 0j) * (Z ^ I ^ I ^ Z) + \ + (400000 + 0j) * (Z ^ I ^ Z ^ I) + \ + (600000 + 0j) * (Z ^ Z ^ I ^ I) OFFSET_MAXIMIZE_SAMPLE = 1149998 @@ -434,9 +428,13 @@ def test_optimizationproblem_to_ising(self): # the encoder uses a dictionary, in which the order of items in Python 3.5 is not # maintained, therefore don't do a list compare but dictionary compare - qubit_op_as_dict = dict(qubitop.paulis) - for coeff, paulis in QUBIT_OP_MAXIMIZE_SAMPLE.paulis: - self.assertEqual(paulis, qubit_op_as_dict[coeff]) + # qubit_op_as_dict = dict(qubitop.paulis) + # for coeff, paulis in QUBIT_OP_MAXIMIZE_SAMPLE.paulis: + # self.assertEqual(paulis, qubit_op_as_dict[coeff]) + print(qubitop.reduce()) + print(qubitop.simplify()) + print(QUBIT_OP_MAXIMIZE_SAMPLE.reduce()) + self.assertEqual(qubitop, QUBIT_OP_MAXIMIZE_SAMPLE) self.assertEqual(offset, OFFSET_MAXIMIZE_SAMPLE) From 4b0232f905826201cd8c642084a2be4c20e06942 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 09:21:10 +0200 Subject: [PATCH 02/27] directly use new opflow, no need to go via WPO --- test/optimization/test_qaoa.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/optimization/test_qaoa.py b/test/optimization/test_qaoa.py index 3d9aa33ab7..3b478fe6d5 100755 --- a/test/optimization/test_qaoa.py +++ b/test/optimization/test_qaoa.py @@ -26,7 +26,7 @@ from qiskit.aqua.components.optimizers import COBYLA from qiskit.aqua.algorithms import QAOA from qiskit.aqua import QuantumInstance, aqua_globals -from qiskit.aqua.operators import WeightedPauliOperator, X, Z +from qiskit.aqua.operators import X, Z, I W1 = np.array([ [0, 1, 0, 1], @@ -35,11 +35,7 @@ [1, 0, 1, 0] ]) P1 = 1 -M1 = WeightedPauliOperator.from_dict({'paulis': [{'label': 'IIIX', 'coeff': {'real': 1}}, - {'label': 'IIXI', 'coeff': {'real': 1}}, - {'label': 'IXII', 'coeff': {'real': 1}}, - {'label': 'XIII', 'coeff': {'real': 1}}] - }).to_opflow() +M1 = I ^ I ^ I ^ X + I ^ I ^ X ^ I + I ^ X ^ I ^ I + X ^ I ^ I ^ I S1 = {'0101', '1010'} From 211aebdbbf7760e045a29fd02179635fe766d9e5 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 09:21:33 +0200 Subject: [PATCH 03/27] update comments and docstrings --- qiskit/aqua/operators/list_ops/summed_op.py | 32 +++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index de2b5760f5..e935ea04ea 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -113,14 +113,17 @@ def simplify(self) -> 'SummedOp': coeffs.append(self.coeff) return SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore - # Try collapsing list or trees of Sums. # TODO be smarter about the fact that any two ops in oplist could be evaluated for sum. def reduce(self) -> OperatorBase: - # first reduce constituents - reduced_ops = [op.reduce() for op in self.oplist] - reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff + """Try collapsing list or trees of sums. - # then group duplicate operators + Tries to sum up duplicate operators and reduces the operators + in the sum. + + Returns: + A collapsed version of self, if possible. + """ + # group duplicate operators # e.g., ``SummedOp([2 * X ^ Y, X ^ Y]).simplify() -> SummedOp([3 * X ^ Y])``. oplist = [] # type: List[OperatorBase] coeffs = [] # type: List[Union[int, float, complex, ParameterExpression]] @@ -143,6 +146,10 @@ def reduce(self) -> OperatorBase: coeffs.append(self.coeff) reduced_ops = SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore + # reduce constituents + reduced_ops = [op.reduce() for op in self.oplist] + reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff + if isinstance(reduced_ops, SummedOp) and len(reduced_ops.oplist) == 1: return reduced_ops.oplist[0] else: @@ -169,6 +176,21 @@ def to_legacy_op(self, massive: bool = False) -> LegacyBaseOperator: return self.combo_fn(legacy_ops) * coeff def equals(self, other: OperatorBase) -> bool: + """Check if other is equal to self. + + Args: + other: The other operator to check for equality. + + Returns: + True, if other and self are equal, otherwise False. + + Examples: + >>> from qiskit.aqua.operators import X, Z + >>> 2 * X == X + X + True + >>> X + Z == Z + X + True + """ self_reduced, other_reduced = self.reduce(), other.reduce() if not isinstance(other_reduced, type(self_reduced)): return False From ffa502025c0ac510ce02d665423f04eca9f829d3 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 09:22:04 +0200 Subject: [PATCH 04/27] directly use opflow --- test/optimization/test_docplex.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/optimization/test_docplex.py b/test/optimization/test_docplex.py index fdc7f6c181..b21a90a68e 100755 --- a/test/optimization/test_docplex.py +++ b/test/optimization/test_docplex.py @@ -26,15 +26,11 @@ from qiskit.aqua import AquaError, aqua_globals from qiskit.aqua.algorithms import NumPyMinimumEigensolver from qiskit.optimization.applications.ising import docplex, tsp -from qiskit.aqua.operators import WeightedPauliOperator +from qiskit.aqua.operators import WeightedPauliOperator, I, Z # Reference operators and offsets for maxcut and tsp. -QUBIT_OP_MAXCUT = WeightedPauliOperator( - paulis=[[0.5, Pauli(z=[True, True, False, False], x=[False, False, False, False])], - [0.5, Pauli(z=[True, False, True, False], x=[False, False, False, False])], - [0.5, Pauli(z=[False, True, True, False], x=[False, False, False, False])], - [0.5, Pauli(z=[True, False, False, True], x=[False, False, False, False])], - [0.5, Pauli(z=[False, False, True, True], x=[False, False, False, False])]]) +QUBIT_OP_MAXCUT = 0.5 * ((I ^ I ^ Z ^ Z) + (I ^ Z ^ I ^ Z) + (I ^ Z ^ Z ^ I) + (Z ^ I ^ I ^ Z) + + (Z ^ Z ^ I ^ I)) OFFSET_MAXCUT = -2.5 QUBIT_OP_TSP = WeightedPauliOperator( paulis=[[-100057.0, Pauli(z=[True, False, False, False, False, False, False, False, False], From 3e2423163a0f014b70c8f73df93d3be48902bc4e Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 10:42:10 +0200 Subject: [PATCH 05/27] don't do equality check in add --- qiskit/aqua/operators/list_ops/summed_op.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index e935ea04ea..eb5ae2fa7a 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -72,9 +72,6 @@ def add(self, other: OperatorBase) -> OperatorBase: Returns: A ``SummedOp`` equivalent to the sum of self and other. """ - if self == other: - return self.mul(2.0) - self_new_ops = self.oplist if self.coeff == 1 \ else [op.mul(self.coeff) for op in self.oplist] if isinstance(other, SummedOp): @@ -147,8 +144,8 @@ def reduce(self) -> OperatorBase: reduced_ops = SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore # reduce constituents - reduced_ops = [op.reduce() for op in self.oplist] - reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff + reduced_ops = [op.reduce() for op in reduced_ops.oplist] + reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * reduced_ops.coeff if isinstance(reduced_ops, SummedOp) and len(reduced_ops.oplist) == 1: return reduced_ops.oplist[0] From 4c6597de5c6edb8422b5d770227fb871cb13c19a Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 10:46:45 +0200 Subject: [PATCH 06/27] directly use opflow --- test/optimization/test_docplex.py | 141 ++++++++++-------------------- 1 file changed, 48 insertions(+), 93 deletions(-) diff --git a/test/optimization/test_docplex.py b/test/optimization/test_docplex.py index b21a90a68e..e10a33c7af 100755 --- a/test/optimization/test_docplex.py +++ b/test/optimization/test_docplex.py @@ -21,108 +21,63 @@ import networkx as nx import numpy as np from docplex.mp.model import Model -from qiskit.quantum_info import Pauli from qiskit.aqua import AquaError, aqua_globals from qiskit.aqua.algorithms import NumPyMinimumEigensolver from qiskit.optimization.applications.ising import docplex, tsp -from qiskit.aqua.operators import WeightedPauliOperator, I, Z +from qiskit.aqua.operators import I, Z # Reference operators and offsets for maxcut and tsp. QUBIT_OP_MAXCUT = 0.5 * ((I ^ I ^ Z ^ Z) + (I ^ Z ^ I ^ Z) + (I ^ Z ^ Z ^ I) + (Z ^ I ^ I ^ Z) + (Z ^ Z ^ I ^ I)) OFFSET_MAXCUT = -2.5 -QUBIT_OP_TSP = WeightedPauliOperator( - paulis=[[-100057.0, Pauli(z=[True, False, False, False, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100071.0, Pauli(z=[False, False, False, False, True, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.5, Pauli(z=[True, False, False, False, True, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100057.0, Pauli(z=[False, True, False, False, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100071.0, Pauli(z=[False, False, False, False, False, True, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.5, Pauli(z=[False, True, False, False, False, True, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100057.0, Pauli(z=[False, False, True, False, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100071.0, Pauli(z=[False, False, False, True, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.5, Pauli(z=[False, False, True, True, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100070.0, Pauli(z=[False, False, False, False, False, False, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.0, Pauli(z=[True, False, False, False, False, False, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [-100070.0, Pauli(z=[False, False, False, False, False, False, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [14.0, Pauli(z=[False, True, False, False, False, False, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [-100070.0, Pauli(z=[False, False, False, False, False, False, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.0, Pauli(z=[False, False, True, False, False, False, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.5, Pauli(z=[False, True, False, True, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.5, Pauli(z=[False, False, True, False, True, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.5, Pauli(z=[True, False, False, False, False, True, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [21.0, Pauli(z=[False, False, False, True, False, False, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [21.0, Pauli(z=[False, False, False, False, True, False, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [21.0, Pauli(z=[False, False, False, False, False, True, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.0, Pauli(z=[False, True, False, False, False, False, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.0, Pauli(z=[False, False, True, False, False, False, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [14.0, Pauli(z=[True, False, False, False, False, False, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [21.0, Pauli(z=[False, False, False, False, True, False, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [21.0, Pauli(z=[False, False, False, False, False, True, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [21.0, Pauli(z=[False, False, False, True, False, False, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[True, False, False, True, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[True, False, False, False, False, False, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, True, False, False, True, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, True, False, False, True, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, True, False, False, False, False, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, False, True, False, False, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, True, False, False, True, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, True, False, False, False, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, False, False, True, False, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[True, True, False, False, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[True, False, True, False, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, True, True, False, False, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, True, True, False, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, True, False, True, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, False, True, True, False, False, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, False, False, False, True, True, False], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, False, False, False, True, False, True], - x=[False, False, False, False, False, False, False, False, False])], - [50000.0, Pauli(z=[False, False, False, False, False, False, False, True, True], - x=[False, False, False, False, False, False, False, False, False])]]) +QUBIT_OP_TSP = ( + -100057.0 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) + + -100071.0 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + + 14.5 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ I ^ Z) + + -100057.0 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) + + -100071.0 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + + 14.5 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ Z ^ I) + + -100057.0 * (I ^ I ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) + + -100071.0 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) + + 14.5 * (I ^ I ^ I ^ I ^ I ^ Z ^ Z ^ I ^ I) + + -100070.0 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + + 14.0 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) + + -100070.0 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ I) + + 14.0 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) + + -100070.0 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) + + 14.0 * (I ^ I ^ Z ^ I ^ I ^ I ^ Z ^ I ^ I) + + 14.5 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ Z ^ I) + + 14.5 * (I ^ I ^ I ^ I ^ Z ^ I ^ Z ^ I ^ I) + + 14.5 * (I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I ^ Z) + + 21.0 * (I ^ Z ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) + + 21.0 * (Z ^ I ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + + 21.0 * (I ^ I ^ Z ^ Z ^ I ^ I ^ I ^ I ^ I) + + 14.0 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ Z ^ I) + + 14.0 * (I ^ Z ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) + + 14.0 * (Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I ^ Z) + + 21.0 * (I ^ I ^ Z ^ I ^ Z ^ I ^ I ^ I ^ I) + + 21.0 * (I ^ Z ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + + 21.0 * (Z ^ I ^ I ^ I ^ I ^ Z ^ I ^ I ^ I) + + 50000.0 * (I ^ I ^ I ^ I ^ I ^ Z ^ I ^ I ^ Z) + + 50000.0 * (I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I ^ Z) + + 50000.0 * (I ^ I ^ Z ^ I ^ I ^ Z ^ I ^ I ^ I) + + 50000.0 * (I ^ I ^ I ^ I ^ Z ^ I ^ I ^ Z ^ I) + + 50000.0 * (I ^ Z ^ I ^ I ^ I ^ I ^ I ^ Z ^ I) + + 50000.0 * (I ^ Z ^ I ^ I ^ Z ^ I ^ I ^ I ^ I) + + 50000.0 * (I ^ I ^ I ^ Z ^ I ^ I ^ Z ^ I ^ I) + + 50000.0 * (Z ^ I ^ I ^ I ^ I ^ I ^ Z ^ I ^ I) + + 50000.0 * (Z ^ I ^ I ^ Z ^ I ^ I ^ I ^ I ^ I) + + 50000.0 * (I ^ I ^ I ^ I ^ I ^ I ^ I ^ Z ^ Z) + + 50000.0 * (I ^ I ^ I ^ I ^ I ^ I ^ Z ^ I ^ Z) + + 50000.0 * (I ^ I ^ I ^ I ^ I ^ I ^ Z ^ Z ^ I) + + 50000.0 * (I ^ I ^ I ^ I ^ Z ^ Z ^ I ^ I ^ I) + + 50000.0 * (I ^ I ^ I ^ Z ^ I ^ Z ^ I ^ I ^ I) + + 50000.0 * (I ^ I ^ I ^ Z ^ Z ^ I ^ I ^ I ^ I) + + 50000.0 * (I ^ Z ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) + + 50000.0 * (Z ^ I ^ Z ^ I ^ I ^ I ^ I ^ I ^ I) + + 50000.0 * (Z ^ Z ^ I ^ I ^ I ^ I ^ I ^ I ^ I) +) OFFSET_TSP = 600279.0 From 951efb9c89e37163b7d9c152984d38cbad79ca00 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 12:23:06 +0200 Subject: [PATCH 07/27] change order in reduce --- qiskit/aqua/operators/list_ops/summed_op.py | 56 ++++++++++++--------- test/aqua/operators/test_op_construction.py | 20 +++++--- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index eb5ae2fa7a..47e4e50697 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -120,36 +120,44 @@ def reduce(self) -> OperatorBase: Returns: A collapsed version of self, if possible. """ + print('in') + print(self) + # reduce constituents + reduced_ops = [op.reduce() for op in self.oplist] + reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff + + # grouped_op = self # group duplicate operators # e.g., ``SummedOp([2 * X ^ Y, X ^ Y]).simplify() -> SummedOp([3 * X ^ Y])``. - oplist = [] # type: List[OperatorBase] - coeffs = [] # type: List[Union[int, float, complex, ParameterExpression]] - for op in self.oplist: - if isinstance(op, PrimitiveOp): - new_op = PrimitiveOp(op.primitive) - new_coeff = op.coeff * self.coeff - if new_op in oplist: - index = oplist.index(new_op) - coeffs[index] += new_coeff - else: - oplist.append(new_op) - coeffs.append(new_coeff) - else: - if op in oplist: - index = oplist.index(op) - coeffs[index] += self.coeff - else: - oplist.append(op) - coeffs.append(self.coeff) - reduced_ops = SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore - - # reduce constituents - reduced_ops = [op.reduce() for op in reduced_ops.oplist] - reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * reduced_ops.coeff + # oplist = [] # type: List[OperatorBase] + # coeffs = [] # type: List[Union[int, float, complex, ParameterExpression]] + # for op in self.oplist: + # if isinstance(op, PrimitiveOp): + # new_op = PrimitiveOp(op.primitive) + # new_coeff = op.coeff * self.coeff + # if new_op in oplist: + # index = oplist.index(new_op) + # coeffs[index] += new_coeff + # else: + # oplist.append(new_op) + # coeffs.append(new_coeff) + # else: + # if op in oplist: + # index = oplist.index(op) + # coeffs[index] += self.coeff + # else: + # oplist.append(op) + # coeffs.append(self.coeff) + # grouped_op = SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore + + # if isinstance(reduced_ops, SummedOp): + # reduced_ops = reduced_ops.simplify() if isinstance(reduced_ops, SummedOp) and len(reduced_ops.oplist) == 1: + print('out', reduced_ops.oplist[0]) return reduced_ops.oplist[0] else: + print('out', reduced_ops) return cast(OperatorBase, reduced_ops) def to_legacy_op(self, massive: bool = False) -> LegacyBaseOperator: diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 5d3cee4881..1a91981235 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -257,11 +257,17 @@ def test_summed_op(self): self.assertListEqual([op.coeff for op in sum_op], [2, 2]) sum_op = (X ^ X * 2) + (Y ^ Y) - sum_op += (Y ^ Y) + (X ^ X * 2) # if self == other the summed op directly multiplied by 2 - with self.subTest('SummedOp test 3'): - self.assertEqual(sum_op.coeff, 2) + sum_op += (Y ^ Y) + (X ^ X * 2) + with self.subTest('SummedOp test 3-a'): + self.assertEqual(sum_op.coeff, 1) + self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'YY', 'XX']) + self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1, 2]) + + sum_op = sum_op.reduce() + with self.subTest('SummedOp test 3-b'): + self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) - self.assertListEqual([op.coeff for op in sum_op], [2, 1]) + self.assertListEqual([op.coeff for op in sum_op], [4, 2]) sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) with self.subTest('SummedOp test 4-a'): @@ -304,9 +310,9 @@ def test_summed_op(self): sum_op = SummedOp([X ^ X * 2, Y ^ Y], 2) sum_op += sum_op with self.subTest('SummedOp test 7-a'): - self.assertEqual(sum_op.coeff, 4) - self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) - self.assertListEqual([op.coeff for op in sum_op], [2, 1]) + self.assertEqual(sum_op.coeff, 1) + self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'XX', 'YY']) + self.assertListEqual([op.coeff for op in sum_op], [4, 2, 4, 2]) sum_op = sum_op.simplify() with self.subTest('SummedOp test 7-b'): From c4b3ca7a8cf8bf96b0b42ff8dcd00c77596f247a Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 12:34:46 +0200 Subject: [PATCH 08/27] fix qaoa --- test/optimization/test_qaoa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/optimization/test_qaoa.py b/test/optimization/test_qaoa.py index 3b478fe6d5..08778ed8c0 100755 --- a/test/optimization/test_qaoa.py +++ b/test/optimization/test_qaoa.py @@ -35,7 +35,7 @@ [1, 0, 1, 0] ]) P1 = 1 -M1 = I ^ I ^ I ^ X + I ^ I ^ X ^ I + I ^ X ^ I ^ I + X ^ I ^ I ^ I +M1 = (I ^ I ^ I ^ X) + (I ^ I ^ X ^ I) + (I ^ X ^ I ^ I) + (X ^ I ^ I ^ I) S1 = {'0101', '1010'} From 6678df1c586ce52afdab8e017c042e6130c294ba Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 12:35:04 +0200 Subject: [PATCH 09/27] add short test on summed op equality --- test/aqua/operators/test_op_construction.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 1a91981235..e1619f7095 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -235,7 +235,7 @@ def test_circuit_permute(self): c_op_id = c_op_perm.permute(perm) self.assertEqual(c_op, c_op_id) - def test_summed_op(self): + def test_summed_op_reduce(self): """Test SummedOp""" sum_op = (X ^ X * 2) + (Y ^ Y) # type: SummedOp with self.subTest('SummedOp test 1'): @@ -332,6 +332,14 @@ def test_summed_op(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_summed_op_equals(self): + """Test corner cases of SummedOp's equals function.""" + with self.subTest('multiplicative factor'): + self.assertEqual(2 * X, X + X) + + with self.subTest('commutative'): + self.assertEqual(X + Z, Z + X) + def test_circuit_compose_register_independent(self): """Test that CircuitOp uses combines circuits independent of the register. From d2865d6f28a785e15ea671e4436d7f3fcd3c7ac3 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 12:42:17 +0200 Subject: [PATCH 10/27] rm prints --- test/optimization/test_converters.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/optimization/test_converters.py b/test/optimization/test_converters.py index abe2efa3cd..dd8d97d258 100644 --- a/test/optimization/test_converters.py +++ b/test/optimization/test_converters.py @@ -431,9 +431,6 @@ def test_optimizationproblem_to_ising(self): # qubit_op_as_dict = dict(qubitop.paulis) # for coeff, paulis in QUBIT_OP_MAXIMIZE_SAMPLE.paulis: # self.assertEqual(paulis, qubit_op_as_dict[coeff]) - print(qubitop.reduce()) - print(qubitop.simplify()) - print(QUBIT_OP_MAXIMIZE_SAMPLE.reduce()) self.assertEqual(qubitop, QUBIT_OP_MAXIMIZE_SAMPLE) self.assertEqual(offset, OFFSET_MAXIMIZE_SAMPLE) From 87f5448de765771082b3c1fe4d87ed0aae54b2ac Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 12:46:47 +0200 Subject: [PATCH 11/27] use set comparison, rename simplify to collapse_summands --- qiskit/aqua/operators/list_ops/summed_op.py | 47 +++------------------ test/aqua/operators/test_op_construction.py | 12 +++--- 2 files changed, 12 insertions(+), 47 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 47e4e50697..39cc4a0d4e 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -81,10 +81,10 @@ def add(self, other: OperatorBase) -> OperatorBase: other_new_ops = [other] return SummedOp(self_new_ops + other_new_ops) - def simplify(self) -> 'SummedOp': + def collapse_summands(self) -> 'SummedOp': """Return Operator by simplifying duplicate operators. - E.g., ``SummedOp([2 * X ^ Y, X ^ Y]).simplify() -> SummedOp([3 * X ^ Y])``. + E.g., ``SummedOp([2 * X ^ Y, X ^ Y]).collapse_summands() -> SummedOp([3 * X ^ Y])``. Returns: A simplified ``SummedOp`` equivalent to self. @@ -120,44 +120,17 @@ def reduce(self) -> OperatorBase: Returns: A collapsed version of self, if possible. """ - print('in') - print(self) # reduce constituents reduced_ops = [op.reduce() for op in self.oplist] reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff - # grouped_op = self # group duplicate operators - # e.g., ``SummedOp([2 * X ^ Y, X ^ Y]).simplify() -> SummedOp([3 * X ^ Y])``. - # oplist = [] # type: List[OperatorBase] - # coeffs = [] # type: List[Union[int, float, complex, ParameterExpression]] - # for op in self.oplist: - # if isinstance(op, PrimitiveOp): - # new_op = PrimitiveOp(op.primitive) - # new_coeff = op.coeff * self.coeff - # if new_op in oplist: - # index = oplist.index(new_op) - # coeffs[index] += new_coeff - # else: - # oplist.append(new_op) - # coeffs.append(new_coeff) - # else: - # if op in oplist: - # index = oplist.index(op) - # coeffs[index] += self.coeff - # else: - # oplist.append(op) - # coeffs.append(self.coeff) - # grouped_op = SummedOp([op * coeff for op, coeff in zip(oplist, coeffs)]) # type: ignore - - # if isinstance(reduced_ops, SummedOp): - # reduced_ops = reduced_ops.simplify() + if isinstance(reduced_ops, SummedOp): + reduced_ops = reduced_ops.collapse_summands() if isinstance(reduced_ops, SummedOp) and len(reduced_ops.oplist) == 1: - print('out', reduced_ops.oplist[0]) return reduced_ops.oplist[0] else: - print('out', reduced_ops) return cast(OperatorBase, reduced_ops) def to_legacy_op(self, massive: bool = False) -> LegacyBaseOperator: @@ -213,13 +186,5 @@ def equals(self, other: OperatorBase) -> bool: if other_reduced.coeff != 1: other_reduced = SummedOp([op * other_reduced.coeff for op in other_reduced.oplist]) - # compare independent of order, for some reason set(...) == set(...) does not work - for op1 in self_reduced.oplist: - found = False - for op2 in other_reduced.oplist: - if op1 == op2: - found = True - break - if not found: - return False - return True + # compare independent of order + return set(self_reduced) == set(other_reduced) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index e1619f7095..741eb4abe6 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -250,7 +250,7 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'YY']) self.assertListEqual([op.coeff for op in sum_op], [2, 1, 1]) - sum_op = sum_op.simplify() + sum_op = sum_op.collapse_summands() with self.subTest('SummedOp test 2-b'): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) @@ -275,7 +275,7 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) self.assertListEqual([op.coeff for op in sum_op], [2, 1]) - sum_op = sum_op.simplify() + sum_op = sum_op.collapse_summands() with self.subTest('SummedOp test 4-b'): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) @@ -288,7 +288,7 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'YY']) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 1]) - sum_op = sum_op.simplify() + sum_op = sum_op.collapse_summands() with self.subTest('SummedOp test 5-b'): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) @@ -301,7 +301,7 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'XX', 'YY']) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 2, 1]) - sum_op = sum_op.simplify() + sum_op = sum_op.collapse_summands() with self.subTest('SummedOp test 6-b'): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) @@ -314,7 +314,7 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'XX', 'YY']) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 4, 2]) - sum_op = sum_op.simplify() + sum_op = sum_op.collapse_summands() with self.subTest('SummedOp test 7-b'): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY']) @@ -326,7 +326,7 @@ def test_summed_op_reduce(self): self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'XX', 'ZZ']) self.assertListEqual([op.coeff for op in sum_op], [4, 2, 6, 3]) - sum_op = sum_op.simplify() + sum_op = sum_op.collapse_summands() with self.subTest('SummedOp test 8-b'): self.assertEqual(sum_op.coeff, 1) self.assertListEqual([str(op.primitive) for op in sum_op], ['XX', 'YY', 'ZZ']) From f34f4ea0d17a6b490426d05b8977980ef2913bb6 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 14:10:16 +0200 Subject: [PATCH 12/27] fix expected value, should be sqrt(2), not 2 --- test/aqua/operators/test_pauli_expectation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/aqua/operators/test_pauli_expectation.py b/test/aqua/operators/test_pauli_expectation.py index 78cda1334e..0002ea5af9 100644 --- a/test/aqua/operators/test_pauli_expectation.py +++ b/test/aqua/operators/test_pauli_expectation.py @@ -89,7 +89,8 @@ def test_pauli_expect_op_vector(self): # !!NOTE!!: Depolarizing channel (Sampling) means interference # does not happen between circuits in sum, so expectation does # not equal expectation for Zero!! - np.testing.assert_array_almost_equal(sampled_zero_mean.eval(), [0, 0, 0, 2], decimal=1) + np.testing.assert_array_almost_equal(sampled_zero_mean.eval(), [0, 0, 0, 2 ** 0.5], + decimal=1) for i, op in enumerate(paulis_op.oplist): mat_op = op.to_matrix() From b5bd373cfeb30bb7500024a26ec2dfc311d74b44 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 14:10:55 +0200 Subject: [PATCH 13/27] cast coeffs to complex --- qiskit/optimization/converters/quadratic_program_to_ising.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index 38098cd407..5655664059 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -114,7 +114,7 @@ def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: shift += weight # Remove paulis whose coefficients are zeros. - qubit_op = sum(PauliOp(pauli, coeff=coeff) for coeff, pauli in pauli_list) + qubit_op = sum(PauliOp(pauli, coeff=complex(coeff)) for coeff, pauli in pauli_list) if len(pauli_list) > 0: # if the list is empty, qubit op is 0 qubit_op = qubit_op.reduce() From a499d0bd1ea9116e763614aeb54803f2fac63d71 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 14:38:57 +0200 Subject: [PATCH 14/27] add reno on equals --- releasenotes/notes/summed-op-compare-3df17046849af9a8.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 releasenotes/notes/summed-op-compare-3df17046849af9a8.yaml diff --git a/releasenotes/notes/summed-op-compare-3df17046849af9a8.yaml b/releasenotes/notes/summed-op-compare-3df17046849af9a8.yaml new file mode 100644 index 0000000000..5fc579a7f5 --- /dev/null +++ b/releasenotes/notes/summed-op-compare-3df17046849af9a8.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + The ``SummedOp`` does a mathematically more correct check for equality, where + expressions such as ``X + X == 2*X`` and ``X + Z == Z + X`` evaluate to ``True``. From eb8ef07a1415a206f0d67eb941d89c823371d6a1 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 17:29:38 +0200 Subject: [PATCH 15/27] fix mypy --- qiskit/aqua/operators/list_ops/summed_op.py | 8 +++++--- .../optimization/converters/quadratic_program_to_ising.py | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 39cc4a0d4e..dfcc5dec17 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -174,17 +174,19 @@ def equals(self, other: OperatorBase) -> bool: return False # check if reduced op is still a SummedOp - if not isinstance(self_reduced, self.__class__): + if not isinstance(self_reduced, SummedOp): return self_reduced == other_reduced + self_reduced = cast(SummedOp, self_reduced) + other_reduced = cast(SummedOp, other_reduced) if not len(self_reduced.oplist) == len(other_reduced.oplist): return False # absorb coeffs into the operators if self_reduced.coeff != 1: - self_reduced = SummedOp([op * self_reduced.coeff for op in self_reduced.oplist]) + self_reduced = SummedOp([op * coeff for op in self_reduced.oplist]) # type: ignore if other_reduced.coeff != 1: - other_reduced = SummedOp([op * other_reduced.coeff for op in other_reduced.oplist]) + other_reduced = SummedOp([op * coeff for op in other_reduced.oplist]) # type: ignore # compare independent of order return set(self_reduced) == set(other_reduced) diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index 5655664059..e767e8345b 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -20,7 +20,7 @@ import numpy as np from qiskit.quantum_info import Pauli -from qiskit.aqua.operators import OperatorBase, PauliOp +from qiskit.aqua.operators import OperatorBase, PauliOp, SummedOp from ..problems.quadratic_program import QuadraticProgram from ..exceptions import QiskitOptimizationError @@ -115,7 +115,7 @@ def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: # Remove paulis whose coefficients are zeros. qubit_op = sum(PauliOp(pauli, coeff=complex(coeff)) for coeff, pauli in pauli_list) - if len(pauli_list) > 0: # if the list is empty, qubit op is 0 + if isinstance(qubit_op, SummedOp): qubit_op = qubit_op.reduce() return qubit_op, shift From 5b77cb6c64194947027745dd8f7b65825b55310e Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 17:32:21 +0200 Subject: [PATCH 16/27] fix spell --- test/optimization/test_converters.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/optimization/test_converters.py b/test/optimization/test_converters.py index dd8d97d258..3702508fcf 100644 --- a/test/optimization/test_converters.py +++ b/test/optimization/test_converters.py @@ -426,13 +426,7 @@ def test_optimizationproblem_to_ising(self): op2 = penalize.encode(op) qubitop, offset = op2ope.encode(op2) - # the encoder uses a dictionary, in which the order of items in Python 3.5 is not - # maintained, therefore don't do a list compare but dictionary compare - # qubit_op_as_dict = dict(qubitop.paulis) - # for coeff, paulis in QUBIT_OP_MAXIMIZE_SAMPLE.paulis: - # self.assertEqual(paulis, qubit_op_as_dict[coeff]) self.assertEqual(qubitop, QUBIT_OP_MAXIMIZE_SAMPLE) - self.assertEqual(offset, OFFSET_MAXIMIZE_SAMPLE) def test_ising_to_quadraticprogram_linear(self): From 596d796305b7074ac786e3c4b058c0afaaf01ce9 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 17:34:11 +0200 Subject: [PATCH 17/27] fix lint --- qiskit/aqua/operators/list_ops/summed_op.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index dfcc5dec17..2391783775 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -184,9 +184,11 @@ def equals(self, other: OperatorBase) -> bool: # absorb coeffs into the operators if self_reduced.coeff != 1: - self_reduced = SummedOp([op * coeff for op in self_reduced.oplist]) # type: ignore + self_reduced = SummedOp( + [op * self_reduced.coeff for op in self_reduced.oplist]) # type: ignore if other_reduced.coeff != 1: - other_reduced = SummedOp([op * coeff for op in other_reduced.oplist]) # type: ignore + other_reduced = SummedOp( + [op * other_reduced.coeff for op in other_reduced.oplist]) # type: ignore # compare independent of order return set(self_reduced) == set(other_reduced) From 0fb497e64744e12c20bd9b4f15be2578a22108e9 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Thu, 18 Jun 2020 18:26:29 +0200 Subject: [PATCH 18/27] dont cast coefficient to complex leads to problems if the coeff is exponentitated and not supposed to be complex --- .../converters/quadratic_program_to_ising.py | 2 +- test/optimization/test_converters.py | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index e767e8345b..645a28c4bd 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -114,7 +114,7 @@ def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: shift += weight # Remove paulis whose coefficients are zeros. - qubit_op = sum(PauliOp(pauli, coeff=complex(coeff)) for coeff, pauli in pauli_list) + qubit_op = sum(PauliOp(pauli, coeff=coeff) for coeff, pauli in pauli_list) if isinstance(qubit_op, SummedOp): qubit_op = qubit_op.reduce() diff --git a/test/optimization/test_converters.py b/test/optimization/test_converters.py index 3702508fcf..4cf01ad572 100644 --- a/test/optimization/test_converters.py +++ b/test/optimization/test_converters.py @@ -37,16 +37,16 @@ logger = logging.getLogger(__name__) -QUBIT_OP_MAXIMIZE_SAMPLE = (-199999.5 + 0j) * (I ^ I ^ I ^ Z) + \ - (-399999.5 + 0j) * (I ^ I ^ Z ^ I) + \ - (-599999.5 + 0j) * (I ^ Z ^ I ^ I) + \ - (-799999.5 + 0j) * (Z ^ I ^ I ^ I) + \ - (100000 + 0j) * (I ^ I ^ Z ^ Z) + \ - (150000 + 0j) * (I ^ Z ^ I ^ Z) + \ - (300000 + 0j) * (I ^ Z ^ Z ^ I) + \ - (200000 + 0j) * (Z ^ I ^ I ^ Z) + \ - (400000 + 0j) * (Z ^ I ^ Z ^ I) + \ - (600000 + 0j) * (Z ^ Z ^ I ^ I) +QUBIT_OP_MAXIMIZE_SAMPLE = -199999.5 * (I ^ I ^ I ^ Z) + \ + -399999.5 * (I ^ I ^ Z ^ I) + \ + -599999.5 * (I ^ Z ^ I ^ I) + \ + -799999.5 * (Z ^ I ^ I ^ I) + \ + 100000 * (I ^ I ^ Z ^ Z) + \ + 150000 * (I ^ Z ^ I ^ Z) + \ + 300000 * (I ^ Z ^ Z ^ I) + \ + 200000 * (Z ^ I ^ I ^ Z) + \ + 400000 * (Z ^ I ^ Z ^ I) + \ + 600000 * (Z ^ Z ^ I ^ I) OFFSET_MAXIMIZE_SAMPLE = 1149998 From 308564b150e46247430c6808663a631efb96faea Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 22 Jun 2020 11:01:55 +0200 Subject: [PATCH 19/27] use sum instead of reduce --- qiskit/aqua/operators/list_ops/summed_op.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 2391783775..6a2342c105 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -121,8 +121,7 @@ def reduce(self) -> OperatorBase: A collapsed version of self, if possible. """ # reduce constituents - reduced_ops = [op.reduce() for op in self.oplist] - reduced_ops = reduce(lambda x, y: x.add(y), reduced_ops) * self.coeff + reduced_ops = sum(op.reduce() for op in self.oplist) * self.coeff # group duplicate operators if isinstance(reduced_ops, SummedOp): From 349dfb160f49591f12732c1a4b70e711f800c892 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 22 Jun 2020 14:22:57 +0200 Subject: [PATCH 20/27] rm unused import --- qiskit/aqua/operators/list_ops/summed_op.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 6a2342c105..d3f4f84524 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -14,7 +14,6 @@ """ SummedOp Class """ -from functools import reduce from typing import List, Union, cast import numpy as np From 892d36f67b76ed48864c582490790e8d21b0fefb Mon Sep 17 00:00:00 2001 From: Cryoris Date: Wed, 24 Jun 2020 18:30:47 +0200 Subject: [PATCH 21/27] move __hash__ to primitive op and base on repr --- qiskit/aqua/operators/primitive_ops/pauli_op.py | 4 ---- qiskit/aqua/operators/primitive_ops/primitive_op.py | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/qiskit/aqua/operators/primitive_ops/pauli_op.py b/qiskit/aqua/operators/primitive_ops/pauli_op.py index 48d8e21a35..b629331cb7 100644 --- a/qiskit/aqua/operators/primitive_ops/pauli_op.py +++ b/qiskit/aqua/operators/primitive_ops/pauli_op.py @@ -231,10 +231,6 @@ def exp_i(self) -> OperatorBase: from ..evolutions.evolved_op import EvolvedOp return EvolvedOp(self) - def __hash__(self) -> int: - # Need this to be able to easily construct AbelianGraphs - return hash(str(self)) - def commutes(self, other_op: OperatorBase) -> bool: """ Returns whether self commutes with other_op. diff --git a/qiskit/aqua/operators/primitive_ops/primitive_op.py b/qiskit/aqua/operators/primitive_ops/primitive_op.py index fa7d5dc61c..08fe9451c2 100644 --- a/qiskit/aqua/operators/primitive_ops/primitive_op.py +++ b/qiskit/aqua/operators/primitive_ops/primitive_op.py @@ -198,6 +198,9 @@ def log_i(self, massive: bool = False) -> OperatorBase: def __str__(self) -> str: raise NotImplementedError + def __hash__(self) -> int: + return hash(repr(self)) + def __repr__(self) -> str: return "{}({}, coeff={})".format(type(self).__name__, repr(self.primitive), self.coeff) From 42d23b9bc03b97733d70ba8535fded0862074a74 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 26 Jun 2020 16:33:31 +0200 Subject: [PATCH 22/27] use != over not == --- qiskit/aqua/operators/list_ops/summed_op.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index d3f4f84524..636975cf6f 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -177,7 +177,7 @@ def equals(self, other: OperatorBase) -> bool: self_reduced = cast(SummedOp, self_reduced) other_reduced = cast(SummedOp, other_reduced) - if not len(self_reduced.oplist) == len(other_reduced.oplist): + if len(self_reduced.oplist) != len(other_reduced.oplist): return False # absorb coeffs into the operators From bc03704c46b3fcce55e3bf47e32635c401c860ca Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 26 Jun 2020 16:39:19 +0200 Subject: [PATCH 23/27] add summed op test for different primitives --- test/aqua/operators/test_op_construction.py | 22 ++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/test/aqua/operators/test_op_construction.py b/test/aqua/operators/test_op_construction.py index 741eb4abe6..ff4f3dcad1 100644 --- a/test/aqua/operators/test_op_construction.py +++ b/test/aqua/operators/test_op_construction.py @@ -14,23 +14,26 @@ """ Test Operator construction, including OpPrimitives and singletons. """ + import unittest from test.aqua import QiskitAquaTestCase import itertools import numpy as np +from ddt import ddt, data from qiskit.circuit import QuantumCircuit, QuantumRegister, Instruction from qiskit.extensions.exceptions import ExtensionError from qiskit.quantum_info.operators import Operator, Pauli -from qiskit.circuit.library import CZGate +from qiskit.circuit.library import CZGate, ZGate from qiskit.aqua.operators import ( - X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp + X, Y, Z, I, CX, T, H, PrimitiveOp, SummedOp, PauliOp, Minus, CircuitOp, MatrixOp ) # pylint: disable=invalid-name +@ddt class TestOpConstruction(QiskitAquaTestCase): """Operator Construction tests.""" @@ -340,6 +343,14 @@ def test_summed_op_equals(self): with self.subTest('commutative'): self.assertEqual(X + Z, Z + X) + with self.subTest('circuit and paulis'): + z = CircuitOp(ZGate()) + self.assertEqual(Z + z, z + Z) + + with self.subTest('matrix op and paulis'): + z = MatrixOp([[1, 0], [0, -1]]) + self.assertEqual(Z + z, z + Z) + def test_circuit_compose_register_independent(self): """Test that CircuitOp uses combines circuits independent of the register. @@ -352,13 +363,14 @@ def test_circuit_compose_register_independent(self): self.assertEqual(composed.num_qubits, 2) - def test_pauli_op_hashing(self): + @data(Z, CircuitOp(ZGate()), MatrixOp([[1, 0], [0, -1]])) + def test_op_hashing(self, op): """Regression test against faulty set comparison. Set comparisons rely on a hash table which requires identical objects to have identical - hashes. Thus, the PauliOp.__hash__ should support this requirement. + hashes. Thus, the PrimitiveOp.__hash__ should support this requirement. """ - self.assertEqual(set([2*Z]), set([2*Z])) + self.assertEqual(set([2 * op]), set([2 * op])) if __name__ == '__main__': From 5a5bf03c79831131578410c41a88b9b8186e72a9 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 26 Jun 2020 16:42:53 +0200 Subject: [PATCH 24/27] check for opbase, not summedop --- qiskit/optimization/converters/quadratic_program_to_ising.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index 645a28c4bd..71bc6e99d8 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -20,7 +20,7 @@ import numpy as np from qiskit.quantum_info import Pauli -from qiskit.aqua.operators import OperatorBase, PauliOp, SummedOp +from qiskit.aqua.operators import OperatorBase, PauliOp from ..problems.quadratic_program import QuadraticProgram from ..exceptions import QiskitOptimizationError @@ -115,7 +115,7 @@ def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: # Remove paulis whose coefficients are zeros. qubit_op = sum(PauliOp(pauli, coeff=coeff) for coeff, pauli in pauli_list) - if isinstance(qubit_op, SummedOp): + if isinstance(qubit_op, OperatorBase): # qubit_op could be the integer 0 qubit_op = qubit_op.reduce() return qubit_op, shift From b3f389df463797cb83286297034d437fe7457381 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 29 Jun 2020 14:50:34 +0200 Subject: [PATCH 25/27] adress changes from review * explicitly raise an error upon ListOp input * return identity op instead of the int 0 --- .../converters/ising_to_quadratic_program.py | 10 +++++++++- .../converters/quadratic_program_to_ising.py | 9 +++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/qiskit/optimization/converters/ising_to_quadratic_program.py b/qiskit/optimization/converters/ising_to_quadratic_program.py index 7e6678add6..2f90171a81 100644 --- a/qiskit/optimization/converters/ising_to_quadratic_program.py +++ b/qiskit/optimization/converters/ising_to_quadratic_program.py @@ -20,7 +20,7 @@ import numpy as np -from qiskit.aqua.operators import OperatorBase, WeightedPauliOperator, SummedOp +from qiskit.aqua.operators import OperatorBase, WeightedPauliOperator, SummedOp, ListOp from ..problems.quadratic_program import QuadraticProgram from ..exceptions import QiskitOptimizationError @@ -59,10 +59,18 @@ def encode(self, qubit_op: Union[OperatorBase, WeightedPauliOperator], offset: f Raises: QiskitOptimizationError: If there are Pauli Xs in any Pauli term QiskitOptimizationError: If there are more than 2 Pauli Zs in any Pauli term + NotImplementedError: If the input operator is a ListOp """ # Set properties if isinstance(qubit_op, WeightedPauliOperator): qubit_op = qubit_op.to_opflow() + + # No support for ListOp yet, this can be added in future + # pylint: disable=unidiomatic-typecheck + if type(qubit_op) == ListOp: + raise NotImplementedError('Conversion of a ListOp is not supported, convert each ' + 'operator in the ListOp separately.') + self._qubit_op = qubit_op self._offset = copy.deepcopy(offset) self._num_qubits = qubit_op.num_qubits diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index 71bc6e99d8..c31a4bd0dc 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -20,7 +20,7 @@ import numpy as np from qiskit.quantum_info import Pauli -from qiskit.aqua.operators import OperatorBase, PauliOp +from qiskit.aqua.operators import OperatorBase, PauliOp, I from ..problems.quadratic_program import QuadraticProgram from ..exceptions import QiskitOptimizationError @@ -115,7 +115,12 @@ def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: # Remove paulis whose coefficients are zeros. qubit_op = sum(PauliOp(pauli, coeff=coeff) for coeff, pauli in pauli_list) - if isinstance(qubit_op, OperatorBase): # qubit_op could be the integer 0 + + # qubit_op could be the integer 0, in this case return an identity operator of + # appopriate size + if isinstance(qubit_op, OperatorBase): qubit_op = qubit_op.reduce() + else: + qubit_op = I ^ num_nodes return qubit_op, shift From 01008e1ea1269038fdfcb9a70d26dfcd9a9264e7 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Mon, 29 Jun 2020 15:29:48 +0200 Subject: [PATCH 26/27] fix spell --- qiskit/optimization/converters/quadratic_program_to_ising.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/optimization/converters/quadratic_program_to_ising.py b/qiskit/optimization/converters/quadratic_program_to_ising.py index c31a4bd0dc..4a573e2171 100644 --- a/qiskit/optimization/converters/quadratic_program_to_ising.py +++ b/qiskit/optimization/converters/quadratic_program_to_ising.py @@ -117,7 +117,7 @@ def encode(self, op: QuadraticProgram) -> Tuple[OperatorBase, float]: qubit_op = sum(PauliOp(pauli, coeff=coeff) for coeff, pauli in pauli_list) # qubit_op could be the integer 0, in this case return an identity operator of - # appopriate size + # appropriate size if isinstance(qubit_op, OperatorBase): qubit_op = qubit_op.reduce() else: From dc8f68c0b48d9a6f1c0d725bf4de3382d8456520 Mon Sep 17 00:00:00 2001 From: Cryoris Date: Fri, 3 Jul 2020 11:25:54 +0200 Subject: [PATCH 27/27] add note that equals is not mathematically sound --- qiskit/aqua/operators/list_ops/summed_op.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/qiskit/aqua/operators/list_ops/summed_op.py b/qiskit/aqua/operators/list_ops/summed_op.py index 636975cf6f..d8bacf07ef 100644 --- a/qiskit/aqua/operators/list_ops/summed_op.py +++ b/qiskit/aqua/operators/list_ops/summed_op.py @@ -154,6 +154,12 @@ def to_legacy_op(self, massive: bool = False) -> LegacyBaseOperator: def equals(self, other: OperatorBase) -> bool: """Check if other is equal to self. + Note: + This is not a mathematical check for equality. + If ``self`` and ``other`` implement the same operation but differ + in the representation (e.g. different type of summands) + ``equals`` will evaluate to ``False``. + Args: other: The other operator to check for equality.