diff --git a/pytket/extensions/qiskit/backends/aer.py b/pytket/extensions/qiskit/backends/aer.py index ba64c275..2eaa0aa7 100644 --- a/pytket/extensions/qiskit/backends/aer.py +++ b/pytket/extensions/qiskit/backends/aer.py @@ -348,7 +348,14 @@ def get_result(self, handle: ResultHandle, **kwargs: KwargTypes) -> BackendResul raise CircuitNotRunError(handle) res = job.result() - backresults = qiskit_result_to_backendresult(res) + backresults = qiskit_result_to_backendresult( + res, + include_shots=self._supports_shots, + include_counts=self._supports_counts, + include_state=self._supports_state, + include_unitary=self._supports_unitary, + include_density_matrix=self._supports_density_matrix, + ) for circ_index, backres in enumerate(backresults): self._cache[ResultHandle(jobid, circ_index, qubit_n, ppc)][ "result" diff --git a/pytket/extensions/qiskit/result_convert.py b/pytket/extensions/qiskit/result_convert.py index 2e953966..42b38347 100644 --- a/pytket/extensions/qiskit/result_convert.py +++ b/pytket/extensions/qiskit/result_convert.py @@ -26,7 +26,7 @@ from qiskit.result import Result # type: ignore from qiskit.result.models import ExperimentResult # type: ignore -from pytket.circuit import Bit, Qubit, UnitID, Circuit +from pytket.circuit import Bit, Qubit, UnitID from pytket.backends.backendresult import BackendResult from pytket.utils.outcomearray import OutcomeArray @@ -81,9 +81,17 @@ def _result_is_empty_shots(result: ExperimentResult) -> bool: return False +# In some cases, Qiskit returns a result with fields we don't expect - +# for example, a circuit with classical bits run on AerStateBackend will +# return counts (whether or not there were measurements). The include_foo +# arguments should be set based on what the backend supports. def qiskit_experimentresult_to_backendresult( result: ExperimentResult, - ppcirc: Optional[Circuit] = None, + include_counts: bool = True, + include_shots: bool = True, + include_state: bool = True, + include_unitary: bool = True, + include_density_matrix: bool = True, ) -> BackendResult: if not result.success: raise RuntimeError(result.status) @@ -105,16 +113,16 @@ def qiskit_experimentresult_to_backendresult( shots, counts, state, unitary, density_matrix = (None,) * 5 datadict = result.data.to_dict() - if _result_is_empty_shots(result): + if _result_is_empty_shots(result) and include_shots: n_bits = len(c_bits) if c_bits else 0 shots = OutcomeArray.from_readouts( np.zeros((result.shots, n_bits), dtype=np.uint8) ) else: - if "memory" in datadict: + if "memory" in datadict and include_shots: memory = datadict["memory"] shots = _hex_to_outar(memory, width) - elif "counts" in datadict: + elif "counts" in datadict and include_counts: qis_counts = datadict["counts"] counts = Counter( dict( @@ -123,13 +131,13 @@ def qiskit_experimentresult_to_backendresult( ) ) - if "statevector" in datadict: + if "statevector" in datadict and include_state: state = datadict["statevector"].reverse_qargs().data - if "unitary" in datadict: + if "unitary" in datadict and include_unitary: unitary = datadict["unitary"].reverse_qargs().data - if "density_matrix" in datadict: + if "density_matrix" in datadict and include_density_matrix: density_matrix = datadict["density_matrix"].reverse_qargs().data return BackendResult( @@ -140,13 +148,27 @@ def qiskit_experimentresult_to_backendresult( state=state, unitary=unitary, density_matrix=density_matrix, - ppcirc=ppcirc, + ppcirc=None, ) -def qiskit_result_to_backendresult(res: Result) -> Iterator[BackendResult]: +def qiskit_result_to_backendresult( + res: Result, + include_counts: bool = True, + include_shots: bool = True, + include_state: bool = True, + include_unitary: bool = True, + include_density_matrix: bool = True, +) -> Iterator[BackendResult]: for result in res.results: - yield qiskit_experimentresult_to_backendresult(result) + yield qiskit_experimentresult_to_backendresult( + result, + include_counts, + include_shots, + include_state, + include_unitary, + include_density_matrix, + ) def backendresult_to_qiskit_resultdata( diff --git a/tests/qiskit_convert_test.py b/tests/qiskit_convert_test.py index 5dec4e86..e592a6c0 100644 --- a/tests/qiskit_convert_test.py +++ b/tests/qiskit_convert_test.py @@ -549,12 +549,17 @@ def test_convert_result() -> None: qc1.save_state() qisk_result = simulator.run(qc1, shots=10).result() - tk_res = next(qiskit_result_to_backendresult(qisk_result)) + # exclude counts from result (we don't expect them + # for the statevector sim after all) + tk_res = next(qiskit_result_to_backendresult(qisk_result, include_counts=False)) state = tk_res.get_state([Qubit("q2", 1), Qubit("q1", 0), Qubit("q2", 0)]) correct_state = np.zeros(1 << 3, dtype=complex) correct_state[6] = 1 + 0j assert compare_statevectors(state, correct_state) + # also check that we don't return counts in tket result + # even if the qiskit result includes them + assert tk_res._counts is None # check measured qc.measure(qr1[0], cr[0])