Skip to content

Improve interfaces for multiple reference operations.

After a brief discussion during yesterday's developer meeting (2023/07/13), we decided to re-open this issue and update it's contents.

Currently, it is possible to set multiple reference operations for a Schedulable by manually adding timing constraints. For example, one could do

schedule=Schedule("test_schedule")
x0 = schedule.add(X("q0"))
y1 = schedule.add(X("q1"), ref_op=x0, ref_pt="start") 
y0 = schedule.add(Y("q0"), ref_op=x0)
cz = schedule.add(CZ("q0", "q1"))
cz.add_timing_constraints(ref_op=y1)
cz.add_timing_constraints(ref_op=y0)

This will schedule the CZ after both y0 and y1, which is a very useful feature. However, this is (to my knowledge) not documented, which would be very nice.

An even better improvement would be to improve the interface to do this, such as

schedule=Schedule("test_schedule")
x0 = schedule.add(X("q0"))
y1 = schedule.add(X("q1"), ref_op=x0, ref_pt="start") 
y0 = schedule.add(Y("q0"), ref_op=x0)
cz = schedule.add(CZ("q0", "q1"), ref_op=(y0, y1))

which is arguably more intuitive and user-friendly.

Hence, this issue can be broken into two parts:

  • Add the timing_constraints to the documentation about schedule create (might be nice to put it in the Bell state example).
  • Improve the interface for adding multiple reference operations (and other timing constraints).

Previous issue description, which (still) describes the desired functionality

Previous description

Description

Support adding multiple operations as ref_ops in a schedule.

Motivation

Take the following snippet from the documentation

import numpy as np
from quantify_scheduler import Schedule
from quantify_scheduler.operations.gate_library import CZ, Measure, Reset, Rxy, X90

sched = Schedule("Bell experiment")

for acq_idx, theta in enumerate(np.linspace(0, 360, 21)):
    sched.add(Reset(q0, q1))
    sched.add(X90(q0))
    sched.add(X90(q1), ref_pt="start")  # Start at the same time as the other X90
    sched.add(CZ(q0, q1))
    sched.add(Rxy(theta=theta, phi=0, qubit=q0))

    sched.add(Measure(q0, acq_index=acq_idx), label="M q0 {:.2f} deg".format(theta))
    sched.add(  
        Measure(q1, acq_index=acq_idx),
        label="M q1 {:.2f} deg".format(theta),
        ref_pt="start",  # Start at the same time as the other measure
    )
sched

In this case, the two X90 operations are assumed to have the same duration. As an example, lets say that q0 has a weak coupling to its driveline. In this case, we may set its rxy.duration to 80 ns, and that of q1 to 20 ns (the default we use in our lab).

Now, the CZ(q0, q1) will have the X90(q1) as reference operation, so it will be executed 20 ns after X90(q0) and X90(q1) start. Hence, there will be a 60 ns overlap between CZ(q0, q1) and X90(q0). If we swap the order in which we added X90(q0) and X90(q1), all would be fine.

Hence, if we could do something like

sched.add(X90(q0), label="x90_q0")
sched.add(X90(q1), ref_pt="start", label="x90_q1")  # Start at the same time as the other X90
sched.add(CZ(q0, q1), ref_op=("x90_q0", "x90_q1"))

which would schedule the CZ after both reference operations are done, this would be resolved. Of course, a question may be how to handle different ref_pts, like "start".

I'm also open to any alternative implementations that provide a simple way of scheduling relative to multiple operations that are possible already with the current version of quantify.


You can also find us on Slack. For reference, the issues workflow is described in the contribution guidelines.

Edited by Nicolas Piot