openqasm
openqasm copied to clipboard
Locally random circuits
Problem
There are an increasing number of methods that depend upon executing families of closely related circuits. In particular, circuits with random Pauli gates inserted in various locations. This idea comes up in many places, such as the twirling operations in Randomized Benchmarking, Randomized compiling, Pauli-frame randomization, and classical shadows.
While these circuit families seem increasingly important, they present a significant problem to execute because of the sheer volume of circuits involved when expressed in a way which can be efficiently executed on many hardware systems. The problem is effectively one where our typical framing of near-time vs real-time breaks down to some degree. Let me explain.
Say you want to execute circuits of a form like:
░ ┌───┐ ░ ░
q_0: ──■────────░─┤ ├─░───■────────░─
┌─┴─┐ ░ ├───┤ ░ ┌─┴─┐ ░
q_1: ┤ X ├──■───░─┤ ├─░─┤ X ├──■───░─
└───┘┌─┴─┐ ░ ├───┤ ░ └───┘┌─┴─┐ ░
q_2: ─────┤ X ├─░─┤ ├─░──────┤ X ├─░─
└───┘ ░ └───┘ ░ └───┘ ░
where the empty boxes in the middle should be filled by randomly sampling from circuits with each box is replaced by I, X, Y, or Z.
I can express such circuits as a parameterized circuit in OpenQASM by either connecting to a continuous parameter family for U gates or through control-flow operations that can be reduced to straight line code at compile time. If I choose to do the latter, I need to invoke the compiler for each circuit instance. The former may allow the compiler to be called only once, but I still need to send a parameter set to the quantum processor for each instance.
Some of the protocols linked in the first paragraph request that each circuit instance be executed only once (the single-shot regime). This puts an enormous demand on even a near-time system that sends just a set of parameters for each circuit, as the time to send even one set of parameters may be many times the execution time for a single circuit.
The question I have is whether this randomization can be sensibly expressed instead in the real-time domain.
Solutions??
What I have in mind is something like qubit-local random variables, somewhat akin to thread-local variables in other languages. With qubit-local variables we could invent some syntax that effectively amounts to a local choice among gates of equivalent duration, so that the circuit can be globally scheduled even without knowledge of the local randomness. I don't have great syntax ideas at the moment, but we could just go with something like:
qlocal bit[2] pauli_choice = rand(2); // produce 2 random bits
if (pauli_choice = "00") {
id $0;
} else if (pauli_choice = "01") {
x $0;
} else if (pauli_choice = "10") {
y $0;
} else {
x $0;
}
and let the compiler do all the work of realizing that the if blocks only depend on qubit-local variables. But, it would be nice to find an alternative which is more compact, and that more directly connects to this constraint of equivalent durations.
I don't understand why we need a special qlocal modifier if we are already relying on the variable being identified as local by the compiler we might as well define an extern qlocal_rand that is inherently identified as a local extern function in the compiled code for the specific target.
IMO what you are really identifying is the inherent inability of QASM to model all of the control system intricacies.
I also think we need extern here because we also need to specify the distribution to draw from.
@taalexander I was looking for something that didn't rely upon a sufficiently smart compiler, but instead allowed the programmer to be explicit about the parallelize-ability of blocks.
Some other ideas that came out of discussion with @levbishop and @ajavadia:
-
Just do this with
boxand an explicit duration around the control flow. That already signals to the compiler that the contents of the box have a fixed duration, allowing scheduling to proceed. -
Find a way to put this inside of a
defcal. i.e. you might have
defcal randpauli(qubit q) -> bit[2] {
bit[2] pauli_choice = rand(2);
if (pauli_choice == "00") {
X q;
elseif {
// ...
}
return pauli_choice
}
which would get used in a program like a measurement operation. We have already said that control-flow is allowed within defcals for things like defining reset, so long as the duration of the defcal is always computable at compile time.