qiboteam / qibocal

Quantum calibration, characterization and validation module for Qibo.
https://qibo.science
Apache License 2.0
28 stars 6 forks source link

Reactive programming for calibration #748

Open andrea-pasquale opened 5 months ago

andrea-pasquale commented 5 months ago

As we know, calibration is tricky and it requires several experiments that may be connected in a non-trivial way plus error handling. Currently to support dependencies between experiments we can rely on a direct acyclic graph (DAG) implementation which has to be coded through yaml . Lately we also tried to implement error handling, the so called "exceptional flow", by defining validators https://github.com/qiboteam/qibocal/pull/668 such as $\chi^2$ and adding the possibility to change the flow of the DAG mid-execution. One of the limitation of this approach is that everything has to pass through yaml which is not ideal especially if we also need to include if-else statements.

The current layout is missing a mechanism to perform easily closed loop optimizations over one or custom protocols.

It would be helpful to have a higher-level API beyond the protocols execution through a DAG coded in yaml We should be able to handle the following features:

A possible idea that was discussed during a meeting was to use reactive programming to address both the dependencies and the error handling. This might be necessary given that the calibration appears to be an event driven algorithm. Personally I like this idea, I'm currently working on a prototype using https://github.com/ReactiveX/RxPY.

Here is a first sketch of pseudo-code proposed by @alecandido

from qibocal import Routines as r
from qibocal import reactive as rx
from qibocal import Subprograms as p
from qibocal import Subgraphs as g
from qibocal import Program as prog

def f(executor, *params):
    r1 = r.ResSpec()
    if r1 > 5:
        r2 = r.QubSpec()

        executor.schedule(p.RamseyLoop())

r3 = p.RamseyLoop()

r4 = rx(r.Rabi(), dep=r2)

myprog = prog(f, r3, r4)
myprog.execute()

As an initial step I want to remove the DAG from yaml and change it to a sequential execution, all the shenanigans about dependencies and error handling will be reintroduce later through reactive programming. As soon as I have something ready I will open a poc PR.

I'm happy to start/continue the discussion here about the possibility of using reactive programming. Suggestions or features needed are welcomed.

alecandido commented 5 months ago

As discussed, RxPY was just a proposal. Though, searching around, I haven't found anything better (it is true that the Python implementation is not much developed and maintained, but the ReactiveX community is instead sufficiently active).

In any case, removing immediately the DAG, even before reactive, seems a good idea.

andrea-pasquale commented 5 months ago

In any case, removing immediately the DAG, even before reactive, seems a good idea.

Implemented in #749 :)

alecandido commented 5 months ago
  • Change the "calibration flow" depending on the output of nodes
  • Perform closed-loop optimization
  • Handling errors at run-time

Btw, to me the second and third point have always been special cases of the first one. So, I'd say that we never fully implemented the "exceptional flow".

It would be helpful to have a higher-level API beyond the protocols execution through a DAG coded in yaml

And YAML was not required, the runcard could be generated in a dictionary (possible since the very beginning).

  • Compose experiment with standard nodes and more complex structure (including DAG or closed optimization loops)

This is the true point: the composition is currently not very practical. So, we need to design an ergonomic way of going through Qibocal (taking pieces from the library, injecting others in the execution). We need more a hooks' system than an exceptional flow replacement (well, the exceptional flow was kind of a name for the hooks' system, and never completely implemented). And, if we make sure to make it ergonomic, it will be advantageous for everyone (and that's what the reactive part is for, using the correct abstractions instead of reinventing the wheel).