From c93a90c36595bce7637e49cf6d90b9cf92c1656b Mon Sep 17 00:00:00 2001 From: Donny Date: Tue, 28 Apr 2020 17:15:44 -0400 Subject: [PATCH 1/4] Performance improvements: 1) Make CircuitOp composition depend on combine 2) Make cache check in CircuitSampler check id(), not deep equality 3) Make to_circuit with measurement copy and measure, rather than insert into new circuit as instruction. --- qiskit/aqua/operators/converters/circuit_sampler.py | 2 +- qiskit/aqua/operators/primitive_ops/circuit_op.py | 6 +----- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 9 +++++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/qiskit/aqua/operators/converters/circuit_sampler.py b/qiskit/aqua/operators/converters/circuit_sampler.py index 29ab9069dc..3c2ddbeb06 100644 --- a/qiskit/aqua/operators/converters/circuit_sampler.py +++ b/qiskit/aqua/operators/converters/circuit_sampler.py @@ -164,7 +164,7 @@ def convert(self, Returns: The converted Operator with CircuitStateFns replaced by DictStateFns or VectorStateFns. """ - if self._last_op is None or operator != self._last_op: + if self._last_op is None or id(operator) != id(self._last_op): # Clear caches self._last_op = operator self._reduced_op_cache = None diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index f6b3ab8b98..e6da401b0a 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -122,11 +122,7 @@ def compose(self, other: OperatorBase) -> OperatorBase: other = other.to_circuit_op() if isinstance(other, (CircuitOp, CircuitStateFn)): - new_qc = QuantumCircuit(self.num_qubits) - new_qc.append(other.to_instruction(), qargs=range(self.num_qubits)) - new_qc.append(self.to_instruction(), qargs=range(self.num_qubits)) - # TODO Fix, because converting to dag just to append is nuts - new_qc = new_qc.decompose() + new_qc = other.primitive.combine(self.primitive) if isinstance(other, CircuitStateFn): return CircuitStateFn(new_qc, is_measurement=other.is_measurement, diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 1cdf7b9dfc..e46944c381 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -294,10 +294,11 @@ def eval(self, def to_circuit(self, meas: bool = False) -> QuantumCircuit: """ Return QuantumCircuit representing StateFn """ if meas: - qc = QuantumCircuit(self.num_qubits, self.num_qubits) - qc.append(self.to_instruction(), qargs=range(self.primitive.num_qubits)) - qc.measure(qubit=range(self.num_qubits), cbit=range(self.num_qubits)) - return qc.decompose() + from qiskit import ClassicalRegister + meas_qc = self.primitive.copy() + meas_qc.add_register(ClassicalRegister(self.num_qubits)) + meas_qc.measure(qubit=range(self.num_qubits), cbit=range(self.num_qubits)) + return meas_qc else: return self.primitive From 0f28e463333f4c1ec35114eb347ff8224363794b Mon Sep 17 00:00:00 2001 From: Donny Date: Tue, 28 Apr 2020 17:47:28 -0400 Subject: [PATCH 2/4] 1) Fix bug causing CircuitSampler to retranspile over and over. 2) Throw an error if QuantumCircuit with classical bits passed into CircuitStateFn or CircuitOp. --- qiskit/aqua/operators/converters/circuit_sampler.py | 1 + qiskit/aqua/operators/primitive_ops/circuit_op.py | 5 ++++- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/converters/circuit_sampler.py b/qiskit/aqua/operators/converters/circuit_sampler.py index 3c2ddbeb06..7c2f13a115 100644 --- a/qiskit/aqua/operators/converters/circuit_sampler.py +++ b/qiskit/aqua/operators/converters/circuit_sampler.py @@ -170,6 +170,7 @@ def convert(self, self._reduced_op_cache = None self._circuit_ops_cache = None self._transpiled_circ_cache = None + self._transpile_before_bind = True if not self._reduced_op_cache: operator_dicts_replaced = operator.to_circuit_op() diff --git a/qiskit/aqua/operators/primitive_ops/circuit_op.py b/qiskit/aqua/operators/primitive_ops/circuit_op.py index e6da401b0a..09151c7362 100644 --- a/qiskit/aqua/operators/primitive_ops/circuit_op.py +++ b/qiskit/aqua/operators/primitive_ops/circuit_op.py @@ -47,7 +47,7 @@ def __init__(self, coeff: A coefficient multiplying the primitive Raises: - TypeError: invalid parameters. + TypeError: Unsupported primitive, or primitive has ClassicalRegisters. """ if isinstance(primitive, Instruction): qc = QuantumCircuit(primitive.num_qubits) @@ -58,6 +58,9 @@ def __init__(self, raise TypeError('CircuitOp can only be instantiated with ' 'QuantumCircuit, not {}'.format(type(primitive))) + if len(primitive.clbits) != 0: + raise TypeError('CircuitOp does not support QuantumCircuits with ClassicalRegisters.') + super().__init__(primitive, coeff=coeff) def primitive_strings(self) -> Set[str]: diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index e46944c381..38b7afa529 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -46,7 +46,7 @@ def __init__(self, is_measurement: Whether the StateFn is a measurement operator. Raises: - TypeError: invalid parameters. + TypeError: Unsupported primitive, or primitive has ClassicalRegisters. """ if isinstance(primitive, Instruction): qc = QuantumCircuit(primitive.num_qubits) @@ -57,6 +57,9 @@ def __init__(self, raise TypeError('CircuitStateFn can only be instantiated ' 'with QuantumCircuit, not {}'.format(type(primitive))) + if len(primitive.clbits) != 0: + raise TypeError('CircuitOp does not support QuantumCircuits with ClassicalRegisters.') + super().__init__(primitive, coeff=coeff, is_measurement=is_measurement) @staticmethod From cbd4e84fa19eaf47bbffdfc526ccd78977464b1c Mon Sep 17 00:00:00 2001 From: Donny Date: Tue, 28 Apr 2020 17:54:20 -0400 Subject: [PATCH 3/4] Move ClassicalRegister import. --- qiskit/aqua/operators/state_fns/circuit_state_fn.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qiskit/aqua/operators/state_fns/circuit_state_fn.py b/qiskit/aqua/operators/state_fns/circuit_state_fn.py index 38b7afa529..25826f1597 100644 --- a/qiskit/aqua/operators/state_fns/circuit_state_fn.py +++ b/qiskit/aqua/operators/state_fns/circuit_state_fn.py @@ -18,7 +18,7 @@ from typing import Union, Set import numpy as np -from qiskit import QuantumCircuit, BasicAer, execute +from qiskit import QuantumCircuit, BasicAer, execute, ClassicalRegister from qiskit.circuit import Instruction, ParameterExpression from qiskit.extensions import Initialize, IGate @@ -297,7 +297,6 @@ def eval(self, def to_circuit(self, meas: bool = False) -> QuantumCircuit: """ Return QuantumCircuit representing StateFn """ if meas: - from qiskit import ClassicalRegister meas_qc = self.primitive.copy() meas_qc.add_register(ClassicalRegister(self.num_qubits)) meas_qc.measure(qubit=range(self.num_qubits), cbit=range(self.num_qubits)) From ba0965fc8af02d1eee77d5b726b56c1ca1fa9713 Mon Sep 17 00:00:00 2001 From: Manoel Marques Date: Wed, 29 Apr 2020 10:53:35 -0400 Subject: [PATCH 4/4] fix IBMQ unit test imports --- test/aqua/operators/test_pauli_expectation.py | 3 ++- test/aqua/test_vqe.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/aqua/operators/test_pauli_expectation.py b/test/aqua/operators/test_pauli_expectation.py index f20362cb1a..b34d3963d1 100644 --- a/test/aqua/operators/test_pauli_expectation.py +++ b/test/aqua/operators/test_pauli_expectation.py @@ -25,7 +25,7 @@ PauliExpectation, AbelianGrouper, CircuitSampler) -from qiskit import BasicAer, IBMQ +from qiskit import BasicAer # pylint: disable=invalid-name @@ -190,6 +190,7 @@ def test_grouped_pauli_expectation(self): @unittest.skip(reason="IBMQ testing not available in general.") def test_ibmq_grouped_pauli_expectation(self): """ pauli expect op vector state vector test """ + from qiskit import IBMQ p = IBMQ.load_account() backend = p.get_backend('ibmq_qasm_simulator') paulis_op = ListOp([X, Y, Z, I]) diff --git a/test/aqua/test_vqe.py b/test/aqua/test_vqe.py index 68c6013373..19883b9a48 100644 --- a/test/aqua/test_vqe.py +++ b/test/aqua/test_vqe.py @@ -18,7 +18,7 @@ from test.aqua import QiskitAquaTestCase import numpy as np from ddt import ddt, unpack, data -from qiskit import BasicAer, QuantumCircuit, IBMQ +from qiskit import BasicAer, QuantumCircuit from qiskit.circuit import ParameterVector from qiskit.aqua import QuantumInstance, aqua_globals, AquaError @@ -259,6 +259,7 @@ def test_vqe_mes(self): @unittest.skip(reason="IBMQ testing not available in general.") def test_ibmq_vqe(self): """ IBMQ VQE Test """ + from qiskit import IBMQ provider = IBMQ.load_account() backend = provider.get_backend('ibmq_qasm_simulator') var_form = RYRZ(self.qubit_op.num_qubits)