Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support executing circuits with a SamplerV2 instance #1470

Merged
merged 14 commits into from
Oct 25, 2024

Conversation

dcmckayibm
Copy link
Collaborator

@dcmckayibm dcmckayibm commented Sep 21, 2024

This change adds a sampler argument to BaseExperiment.run() which causes that BaseSamplerV2 instance to be used to run the experiment's circuits. Additionally, if no sampler is passed, BaseExperiment.run() defaults to instantiating a qiskit_ibm_runtime.SamplerV2 object and running the circuits with that. qiskit_ibm_runtime.SamplerV2 can execute using IBM Quantum's sampler primitive and can also fall back to calling backend.run for backends that are not representing IBM Quantum devices. A backend_run parameter is also added to BaseExperiment.run() which causes the old backend.run() execution path to be used. For sampler execution, the job results are translated back into the format expected from backend.run so that the remaining analysis code can be used unchanged. Some additional changes have been made to account for differences between backend.run job result classes and primitive job result classes.

@dcmckayibm
Copy link
Collaborator Author

After skimming around this seems like the easiest way without making huge changes

@wshanks
Copy link
Collaborator

wshanks commented Sep 22, 2024

This looks reasonable to me. I would consider taking sampler as an argument though. That way a user can pass a different sampler if necessary, for example the SamplerV2 from Aer. It would also let the user set options on the sampler before passing it in, since the sampler has a complicated options structure that is hard to map onto the flat run_options format that was used for backend.run.

A downside to this suggestion is then the user has to pass both the backend and the sampler. The code could try to use sampler._backend for the backend. That exists for the qiskit-ibm-runtime and qiskit-aer samplers so covers all current cases that I know of, but _backend is not specified in the SamplerV2 base class so I would fall back to the backend argument if hasattr(sampler, "_backend") is false.

Did you test a parallel experiment? Maybe join_data does the right thing? It is not efficient since it is joining the registers and then marginalizing them instead of using the already margninalized results that the sampler returns but that is fine for now.

It would be nice to have a test assuming the qiskit-ibm-runtime and qiskit-aer samplers work similarly enough.

qiskit_experiments/framework/experiment_data.py Outdated Show resolved Hide resolved
qiskit_experiments/framework/experiment_data.py Outdated Show resolved Hide resolved
qiskit_experiments/framework/experiment_data.py Outdated Show resolved Hide resolved
qiskit_experiments/framework/base_experiment.py Outdated Show resolved Hide resolved
@dcmckayibm
Copy link
Collaborator Author

@wshanks I tested with the t1 notebook here https://github.com/qiskit-community/qiskit-device-benchmarking/blob/main/notebooks/bell_tphi.ipynb and it worked fine.

@dcmckayibm
Copy link
Collaborator Author

I changed this up a bit. There's now a flag to use backend.run since that will be the outlier and we will have to retire it completely soon. You can pass in a sampler ... didn't resolve what @wshanks was worried about with the backend getting pulled from the sampler.

Copy link
Collaborator

@wshanks wshanks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this is merged, there should be release note added for how to work with the sampler. I am trying to summarize the supported paths after this PR:

  1. backend.run -- if you pass backend_run=True to an experiment's run() method, the experiment will run as it has in the past. You could also pass backend_run=True to the experiment's __init__ but most experiments don't do super().__init__(**kwargs) so the backend_run would not get passed up to BaseExperiment.__init__. We could treat backend_run with experiment_options but the usefulness of backend.run diminishes greatly very soon so it is probably not worth much effort.
  2. qiskit_ibm_runtime.SamplerV2 -- one can pass a qiskit_ibm_runtime.SamplerV2 to an experiment's run() method. That sampler will get used to run the jobs (as long as backend_run=True was not also used).
  3. Default case -- if a backend was already set on the experiment and it is called without passing a backend or sampler, a qiskit_ibm_runtime.SamplerV2 is created on the fly and some options are translated into sampler options for it. Then it is used to run the jobs.
  4. Alternative sampler implementation -- there is no way to pass an alternative sampler implementation. The current code will ignore it and generate a new qiskit_ibm_runtime.SamplerV2 to execute with instead.

if not self._backend_run:
if sampler is None:
# instantiate a sampler from the backend
sampler = Sampler(self.backend)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I was expecting a check for qiskit_ibm_runtime.IBMBackend and giving an error otherwise. I see though that qiskit-ibm-runtime does that check itself and re-routes down a local path if it is passed a backend that is not a qiskit_ibm_runtime.IBMBackend`. I have not played with that. I suppose it works well enough? Aer also has its own primitive implementations that might be more efficient so the tests probably should be switched to those some time.

qiskit_experiments/framework/base_experiment.py Outdated Show resolved Hide resolved
* Patch ExperimentData.completion_times to handle Job.time_per_step not
  existing
* Pass noise_model run option through to Sampler
* Add support for level 1 data to Sampler execution
* Handle case where the Sampler strips circuit metadata from results
* Mark some test backends as simulators so the sampler does not try to
  validate circuits
* Change some tests to be more consistent about shots since the Sampler
  can not handle the requested number of shots differing from the shots
in the actual results.
* Support level 2 bitstrings in MockIQBackend
* Fix PulseBackend returning data as numpy array instead of a list
* Pass run options through to backend in T2HahnBackend
* Do not set block_for_results timeout to 0 when TEST_TIMEOUT is 0
  (TEST_TIMEOUT=0 indicates no timeout, not immediate timeout).
* Monkey-patch BackendSamplerV2's run circuits function in the tests so
  that it does not strip circuit metadata that the test backends need to
generate results.
* Fix inconsistency between bitstring format and number of qubits in
  restless test.
* Handle case where job class does not have error_message
These changes could be merged into #1470 (PR could be redirected to that
branch). For now I am just opening a PR to see how the tests run in CI.
@dekelmeirom
Copy link
Contributor

Tested on qiskit-monitoring, and it works great for all of qiskit-monitoring usages!

docs/howtos/runtime_sessions.rst Show resolved Hide resolved
docs/howtos/runtime_sessions.rst Outdated Show resolved Hide resolved
docs/howtos/runtime_sessions.rst Outdated Show resolved Hide resolved
qiskit_experiments/framework/backend_data.py Outdated Show resolved Hide resolved
releasenotes/notes/primitives_add-1a3bcbb2f189d18e.yaml Outdated Show resolved Hide resolved
docs/howtos/runtime_sessions.rst Outdated Show resolved Hide resolved
releasenotes/notes/primitives_add-1a3bcbb2f189d18e.yaml Outdated Show resolved Hide resolved
@wshanks wshanks changed the title WIP: Add the sampler Add support executing circuits with a SamplerV2 instance Oct 24, 2024
@wshanks
Copy link
Collaborator

wshanks commented Oct 24, 2024

I updated the PR description because that is what is used for the commit message when we merge in this repo.

@dcmckayibm dcmckayibm added this pull request to the merge queue Oct 25, 2024
Merged via the queue into main with commit bd05f2a Oct 25, 2024
11 checks passed
@wshanks wshanks deleted the primitives_add branch October 25, 2024 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants