From cdbe300fad98a9d6dbf7a6a6e2a827ce1314aadd Mon Sep 17 00:00:00 2001 From: Andrew Lytle Date: Thu, 30 May 2024 16:51:04 -0500 Subject: [PATCH] estimator_from_aer.py qiskit >=0.46 compatible --- README.md | 48 +++++++----------------------- src/dense_ev/estimator_from_aer.py | 17 +++++++---- src/dense_ev/rmatrix.py | 8 ++--- src/dense_ev/test_estimator.py | 19 ++++++------ 4 files changed, 35 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 492aaf6..bab01c5 100644 --- a/README.md +++ b/README.md @@ -20,52 +20,24 @@ Install from GitHub: ```bash pip install git+ssh://git@github.com/atlytle/dense-ev.git ``` -To run unit tests, +A test function comparing results using abelian and dense grouping +with exact results is available ```python -from dense_ev._test_ops import run_unit_tests +from dense_ev.test_estimator import test_random -run_unit_tests() +m = 3 # n_qubits +run_unit_tests(m) ``` ### Qiskit version compatibility -Note that **dense_ev** specifies `qiskit < 0.43.0`, as the `Opflow` and -`QuantumInstance` packages have been deprecated as of `Qiskit 0.43.0`. -We plan to update the code to function with the new `primitives` as this -migration continues and more documentation becomes available. -**Update 2024-01-07**: Support for dense Pauli grouping +**2024-01-07**: Support for dense Pauli grouping in the Aer `Estimator` primitive merged to `main` branch. -See usage example below. +See usage example below. +**2024-05-30**: Functionality using `Opflow` and other deprecated classes +has been removed. Package requirements changed from `qiskit < 0.43.0` +to `qiskit` (v1.0). Added `qiskit_aer` requirement. ## Usage -Functionality for naive and QWC groupings is provided in Qiskit -by the `PauliExpectation` class. `DensePauliExpectation` extends the functionality -to dense optimal grouping, and may be used as a replacement for -`PauliExpectation`: -```python -from dense_ev.dense_pauli_expectation import DensePauliExpectation - -# Simple expectation values: -... - -ev_spec = StateFn(H).compose(psi) -expectation = DensePauliExpectation().convert(ev_spec) - -... - -# VQE example -... - -vqe = VQE(ansatz, optimizer=spsa, quantum_instance=qi, - callback=store_intermediate_result, - expectation=DensePauliExpectation()) - -result = vqe.compute_minimum_eigenvalue(operator=H) - -... - - -``` - ### Estimator support The Aer implementation of `Estimator` is extended to incorporate dense Pauli grouping, and can be invoked using the keyword diff --git a/src/dense_ev/estimator_from_aer.py b/src/dense_ev/estimator_from_aer.py index 7deab49..dfb50e9 100644 --- a/src/dense_ev/estimator_from_aer.py +++ b/src/dense_ev/estimator_from_aer.py @@ -28,7 +28,7 @@ import numpy as np from qiskit.circuit import ParameterExpression, QuantumCircuit from qiskit.compiler import transpile -from qiskit.opflow import PauliSumOp +#from qiskit.opflow import PauliSumOp from qiskit.primitives import BaseEstimator, EstimatorResult from qiskit.primitives.primitive_job import PrimitiveJob from qiskit.primitives.utils import _circuit_key, _observable_key, init_observable @@ -104,9 +104,11 @@ def __init__( If approximation is True, this parameter is ignored and assumed to be False. """ super().__init__(options=run_options) - # if abelian_grouping == "DENSE": - # m = 3 - # self.PO = PauliOrganizer(m) + # These three private attributes used to be created by super, but were deprecated in Qiskit + # 0.46. See https://github.com/Qiskit/qiskit/pull/11051 + self._circuits = [] + self._parameters = [] + self._observables = [] backend_options = {} if backend_options is None else backend_options method = ( "density_matrix" @@ -148,7 +150,7 @@ def _call( def _run( self, circuits: Sequence[QuantumCircuit], - observables: Sequence[BaseOperator | PauliSumOp], + observables: Sequence[BaseOperator], parameter_values: Sequence[Sequence[float]], **run_options, ) -> PrimitiveJob: @@ -185,7 +187,8 @@ def _run( parameter_values, **run_options, ) - job.submit() + # The public submit method was removed in Qiskit 0.46 + (job.submit if hasattr(job, "submit") else job._submit)() # pylint: disable=no-member return job def _compute(self, circuits, observables, parameter_values, run_options): @@ -394,6 +397,8 @@ def _combine_circs(circuit: QuantumCircuit, meas_circuits: list[QuantumCircuit]) circs = [] for meas_circuit in meas_circuits: new_circ = circuit.copy() + #print(f"{new_circ.num_qubits = }") + #print(f"{meas_circuit.num_qubits = }") for creg in meas_circuit.cregs: new_circ.add_register(creg) new_circ.compose(meas_circuit, inplace=True) diff --git a/src/dense_ev/rmatrix.py b/src/dense_ev/rmatrix.py index 59bb76a..c88ee41 100644 --- a/src/dense_ev/rmatrix.py +++ b/src/dense_ev/rmatrix.py @@ -24,12 +24,12 @@ from numpy.random import normal from scipy.stats import unitary_group -from qiskit.opflow.primitive_ops import PauliOp +#from qiskit.opflow.primitive_ops import PauliOp from qiskit.quantum_info import SparsePauliOp from qiskit.quantum_info.operators import Pauli -from qiskit.opflow.list_ops.summed_op import SummedOp -from qiskit.opflow.primitive_ops.pauli_sum_op import PauliSumOp -from qiskit.opflow.converters import AbelianGrouper +#from qiskit.opflow.list_ops.summed_op import SummedOp +#from qiskit.opflow.primitive_ops.pauli_sum_op import PauliSumOp +#from qiskit.opflow.converters import AbelianGrouper # from qiskit.opflow.converters.pauli_basis_change import PauliBasisChange # from qiskit.opflow.state_fns.state_fn import StateFn diff --git a/src/dense_ev/test_estimator.py b/src/dense_ev/test_estimator.py index 5e65c44..fc68152 100644 --- a/src/dense_ev/test_estimator.py +++ b/src/dense_ev/test_estimator.py @@ -42,14 +42,15 @@ def test_random(m): result_exact = estimator.run(state, H, shots=nshots).result().values # Abelian result. - nshots = 200000 - approx = False - grouping = True - run_options = {"shots": nshots, "seed": seed} - estimator = Estimator( - run_options=run_options, abelian_grouping=grouping, approximation=approx - ) - result_abelian = estimator.run(state, H, shots=nshots).result().values + # nshots = 200000 + # approx = False + # grouping = True + # run_options = {"shots": nshots, "seed": seed} + # estimator = Estimator( + # run_options=run_options, abelian_grouping=grouping, + # approximation=approx + # ) + #result_abelian = estimator.run(state, H, shots=nshots).result().values # Dense result. nshots = 200000 @@ -62,7 +63,7 @@ def test_random(m): result_dense = estimator.run(state, H, shots=nshots).result().values print(f"{result_exact = }") - print(f"{result_abelian = }") + #print(f"{result_abelian = }") print(f"{result_dense = }")