I want to write code that prints out the controls of each operation executed during a simulation in Q#. For example this code prints the control counts:
var qsim = new QCTraceSimulator(config);
qsim.OnOperationStart += (op, arg) => {
Console.WriteLine($"{Controls(op, arg).Length"});
}
I'm having trouble writing the Controls
function, which extracts a list of qubits being used as controls. When the operation is uncontrolled, or controlled by 0 qubits, the returned array should be of length 0.
The issue I'm running into is that the type and layout of arg.Value
varies from operation to operation, even after conditioning on op.Variant
being OperationFunctor.ControlledAdjoint
or OperationFunctor.Controlled
. I can handle individual cases by inspecting the types, but I keep running into new unhandled cases. This indicates there's probably a "correct" way to do this that I'm missing.
In short, how do I implement this function:
object[] Controls(ICallable op, IApplyData arg) {
???
}
By "controls" I always mean the cs
in Controlled Op(cs, ...)
. The same operation may have different controls when expressed in different ways. For example, the controls list of Controlled Toffoli(a, (b, c, d))
is the list [a]
whereas the controls list of Controlled X([a, b, c], d)
is the list [a, b, c]
. A further example: the controls list of Toffoli(b, c, d)
is []
, even though normally one might think of the first two arguments as the controls. It is of course expected that within Toffoli(b, c, d)
there may be a sub-operation Controlled X((b, c), d)
where the controls list is [b, c]
; I'm not thinking of controls as some kind of absolute concept that is invariant as you go down through layers of abstraction.