-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Continuing discussions of #359 with @weinbe58 on how to extract exact probability distributions. #359 is a blocker for QuEraComputing/bloqade#260 "bloqade circuits" tutorial.
In general, extracting out exact probability distributions is a relatively hard problem that requires some abstract analysis, or at least an interpreter that is able to explore an entire (discrete) decision tree based on postselecting measurements. And, of course, it is impossible for continuous random variables (such as Gaussian random coherent noise). A related challenge is unnecessarily repeatedly calling state-vector evolution to query the same state once per shot, but perhaps that's a caching thing that we'll worry about once performance is an issue.
This also gives some motivation for more strongly distinguishing the three types of interpretation on bloqade kernels:
- Hardware - This actually executes a task on Gemini or some other device
- Emulation - A faithful emulator of what running a task on Gemini might be. So, adding circuit noise at the user discretion, as well as not being able to compute exact probability distributions
- Simulation - A "godmode" of emulation where the user is also able to extract and copy the state vector / RDM, as well as extract exact probability distributions if needed.
Phil and I discussed this at length. The challenge is thinking about "where" postprocessing on bitstring measurements happens: server side next to the QPU, or client side. We settled on proposing adding a new dialect squin.unphysical
to squin, which could let the user extract RDMs or probabilities. Further, we concluded post post-processing should occur "outside" of the kernel, on the client side.
probabilities:squin.unphysical.Bitstrings = squin.unphysical.measure([qreg[0],qreg[5],qreg[2],...])
reduced_density_matrix:squin.unphysical.RDM = squin.unphysical.rdm([qreg[0],qreg[5],qreg[2],...])
This unphysical
dialect could be appropriately interpreted by simulation, but not by emulation
or hardware
. The return types could also be rendered uninterpretable to ensure that a user could not use, say, the probability of measuring bitstring 5 to be 0, within that kernel. The only place they could be used is in a return
.
It could also be a relatively simple rewrite to convert a squin.unphysical.measure
statement into a squin.qubit.measure
statement, which would also change the type signature of the returned Bitstrings
to list[bool]
. One could also automatically write the Python function which could do the averaging/frequentist counting as the client side postprocessing on the returned values. Heck, even the rdm could be rewritten into state tomography/shadows to be run through multiple shots on hardware. Generally speaking, it is a compiler pass that is more explicit about postprocessing pipelines, e.g., with a signature kernel, py_func = rewrite(kernel)
.