schedule ======== .. py:module:: quantify_scheduler.schedules.schedule .. autoapi-nested-parse:: Module containing the core concepts of the scheduler. Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: quantify_scheduler.schedules.schedule.ScheduleBase quantify_scheduler.schedules.schedule.Schedule quantify_scheduler.schedules.schedule.Schedulable quantify_scheduler.schedules.schedule.CompiledSchedule quantify_scheduler.schedules.schedule.AcquisitionMetadata .. py:class:: ScheduleBase(dict=None, /, **kwargs) Bases: :py:obj:`quantify_scheduler.json_utils.JSONSchemaValMixin`, :py:obj:`collections.UserDict`, :py:obj:`abc.ABC` Interface to be used for :class:`~.Schedule`. The :class:`~.ScheduleBase` is a data structure that is at the core of the Quantify-scheduler and describes when what operations are applied where. The :class:`~.ScheduleBase` is a collection of :class:`quantify_scheduler.operations.operation.Operation` objects and timing constraints that define relations between the operations. The schedule data structure is based on a dictionary. This dictionary contains: - operation_dict - a hash table containing the unique :class:`quantify_scheduler.operations.operation.Operation` s added to the schedule. - schedulables - a dictionary of all timing constraints added between operations. The :class:`~.Schedule` provides an API to create schedules. The :class:`~.CompiledSchedule` represents a schedule after it has been compiled for execution on a backend. The :class:`~.Schedule` contains information on the :attr:`~.ScheduleBase.operations` and :attr:`~.ScheduleBase.schedulables`. The :attr:`~.ScheduleBase.operations` is a dictionary of all unique operations used in the schedule and contain the information on *what* operation to apply *where*. The :attr:`~.ScheduleBase.schedulables` is a dictionary of Schedulables describing timing constraints between operations, i.e. when to apply an operation. **JSON schema of a valid Schedule** .. jsonschema:: https://gitlab.com/quantify-os/quantify-scheduler/-/raw/main/quantify_scheduler/schemas/schedule.json .. py:property:: name :type: str Returns the name of the schedule. .. py:property:: repetitions :type: int Returns the amount of times this Schedule will be repeated. :returns: The repetitions count. .. py:property:: operations :type: dict[str, quantify_scheduler.operations.operation.Operation] A dictionary of all unique operations used in the schedule. This specifies information on *what* operation to apply *where*. The keys correspond to the :attr:`~.Operation.hash` and values are instances of :class:`quantify_scheduler.operations.operation.Operation`. .. py:property:: schedulables :type: dict[str, Any] A list of schedulables describing the timing of operations. A schedulable uses timing constraints to constrain the operation in time by specifying the time (:code:`"rel_time"`) between a reference operation and the added operation. The time can be specified with respect to a reference point (:code:`"ref_pt"') on the reference operation (:code:`"ref_op"`) and a reference point on the next added operation (:code:`"ref_pt_new"'). A reference point can be either the "start", "center", or "end" of an operation. The reference operation (:code:`"ref_op"`) is specified using its label property. Each item in the list represents a timing constraint and is a dictionary with the following keys: .. code-block:: ['label', 'rel_time', 'ref_op', 'ref_pt_new', 'ref_pt', 'operation_repr'] The label is used as a unique identifier that can be used as a reference for other operations, the operation_repr refers to the string representation of a operation in :attr:`~.ScheduleBase.operations`. .. note:: timing constraints are not intended to be modified directly. Instead use the :meth:`~.Schedule.add` .. py:property:: resources :type: dict[str, quantify_scheduler.resources.Resource] A dictionary containing resources. Keys are names (str), values are instances of :class:`~quantify_scheduler.resources.Resource`. .. py:property:: timing_table :type: pandas.io.formats.style.Styler A styled pandas dataframe containing the absolute timing of pulses and acquisitions in a schedule. This table is constructed based on the abs_time key in the :attr:`~quantify_scheduler.schedules.schedule.ScheduleBase.schedulables`. This requires the timing to have been determined. :param schedule: a schedule for which the absolute timing has been determined. :returns: styled_timing_table, a pandas Styler containing a dataframe with an overview of the timing of the pulses and acquisitions present in the schedule. The data frame can be accessed through the .data attribute of the Styler. :raises ValueError: When the absolute timing has not been determined during compilation. .. py:method:: to_json() -> str Convert the Schedule data structure to a JSON string. :returns: The json string result. .. py:method:: from_json(data: str) -> Schedule :classmethod: Convert the JSON data to a Schedule. :param data: The JSON data. :returns: The Schedule object. .. py:method:: plot_circuit_diagram(figsize: tuple[int, int] = None, ax: matplotlib.axes.Axes | None = None, plot_backend: Literal[mpl] = 'mpl') -> tuple[matplotlib.figure.Figure, matplotlib.axes.Axes | list[matplotlib.axes.Axes]] Create a circuit diagram visualization of the schedule using the specified plotting backend. The circuit diagram visualization depicts the schedule at the quantum circuit layer. Because quantify-scheduler uses a hybrid gate-pulse paradigm, operations for which no information is specified at the gate level are visualized using an icon (e.g., a stylized wavy pulse) depending on the information specified at the quantum device layer. Alias of :func:`quantify_scheduler.schedules._visualization.circuit_diagram.circuit_diagram_matplotlib`. :param schedule: the schedule to render. :param figsize: matplotlib figsize. :param ax: Axis handle to use for plotting. :param plot_backend: Plotting backend to use, currently only 'mpl' is supported :returns: * *fig* -- matplotlib figure object. * *ax* -- matplotlib axis object. Each gate, pulse, measurement, and any other operation are plotted in the order of execution, but no timing information is provided. .. admonition:: Example :class: tip .. jupyter-execute:: from quantify_scheduler import Schedule from quantify_scheduler.operations.gate_library import Reset, X90, CZ, Rxy, Measure sched = Schedule(f"Bell experiment on q0-q1") sched.add(Reset("q0", "q1")) sched.add(X90("q0")) sched.add(X90("q1"), ref_pt="start", rel_time=0) sched.add(CZ(qC="q0", qT="q1")) sched.add(Rxy(theta=45, phi=0, qubit="q0") ) sched.add(Measure("q0", acq_index=0)) sched.add(Measure("q1", acq_index=0), ref_pt="start") sched.plot_circuit_diagram(); .. note:: Gates that are started simultaneously on the same qubit will overlap. .. jupyter-execute:: from quantify_scheduler import Schedule from quantify_scheduler.operations.gate_library import X90, Measure sched = Schedule(f"overlapping gates") sched.add(X90("q0")) sched.add(Measure("q0"), ref_pt="start", rel_time=0) sched.plot_circuit_diagram(); .. note:: If the pulse's port address was not found then the pulse will be plotted on the 'other' timeline. .. py:method:: plot_pulse_diagram(port_list: list[str] | None = None, sampling_rate: float = 1000000000.0, modulation: Literal[off, if, clock] = 'off', modulation_if: float = 0.0, plot_backend: Literal[mpl, plotly] = 'mpl', plot_kwargs: dict | None = None, **backend_kwargs: Any) -> tuple[matplotlib.figure.Figure, matplotlib.axes.Axes] | plotly.graph_objects.Figure Create a visualization of all the pulses in a schedule using the specified plotting backend. The pulse diagram visualizes the schedule at the quantum device layer. For this visualization to work, all operations need to have the information present (e.g., pulse info) to represent these on the quantum-circuit level and requires the absolute timing to have been determined. This information is typically added when the quantum-device level compilation is performed. Alias of :func:`quantify_scheduler.schedules._visualization.pulse_diagram.pulse_diagram_matplotlib` and :func:`quantify_scheduler.schedules._visualization.pulse_diagram.pulse_diagram_plotly`. :param port_list: A list of ports to show. If `None` (default) the first 8 ports encountered in the sequence are used. :param modulation: Determines if modulation is included in the visualization. :param modulation_if: Modulation frequency used when modulation is set to "if". :param sampling_rate: The time resolution used to sample the schedule in Hz. :param plot_backend: Plotting library to use, can either be 'mpl' or 'plotly'. :param plot_kwargs: Keyword arguments to be passed on to the plotting backend. The arguments that can be used for either backend can be found in the documentation of :func:`quantify_scheduler.schedules._visualization.pulse_diagram.pulse_diagram_matplotlib` and :func:`quantify_scheduler.schedules._visualization.pulse_diagram.pulse_diagram_plotly`. :param backend_kwargs: Keyword arguments to be passed on to the plotting backend. The arguments that can be used for either backend can be found in the documentation of :func:`quantify_scheduler.schedules._visualization.pulse_diagram.pulse_diagram_matplotlib` and :func:`quantify_scheduler.schedules._visualization.pulse_diagram.pulse_diagram_plotly`. :returns: the plot :rtype: Union[Tuple[Figure, Axes], :class:`!plotly.graph_objects.Figure`] .. admonition:: Example :class: tip A simple plot with matplotlib can be created as follows: .. jupyter-execute:: from quantify_scheduler.operations.pulse_library import DRAGPulse, SquarePulse, RampPulse from quantify_scheduler.compilation import determine_absolute_timing schedule = Schedule("Multiple waveforms") schedule.add(DRAGPulse(G_amp=0.2, D_amp=0.2, phase=0, duration=4e-6, port="P", clock="C")) schedule.add(RampPulse(amp=0.2, offset=0.0, duration=6e-6, port="P")) schedule.add(SquarePulse(amp=0.1, duration=4e-6, port="Q"), ref_pt='start') determine_absolute_timing(schedule) _ = schedule.plot_pulse_diagram(sampling_rate=20e6) The backend can be changed to the plotly backend by specifying the ``plot_backend=plotly`` argument. With the plotly backend, pulse diagrams include a separate plot for each port/clock combination: .. jupyter-execute:: schedule.plot_pulse_diagram(sampling_rate=20e6, plot_backend='plotly') The same can be achieved in the default ``plot_backend`` (``matplotlib``) by passing the keyword argument ``multiple_subplots=True``: .. jupyter-execute:: _ = schedule.plot_pulse_diagram(sampling_rate=20e6, multiple_subplots=True) .. py:method:: get_schedule_duration() -> float Return the duration of the schedule. :returns: **schedule_duration** -- Duration of current schedule :rtype: float .. py:class:: Schedule(name: str, repetitions: int = 1, data: dict = None) Bases: :py:obj:`ScheduleBase` A modifiable schedule. Operations :class:`quantify_scheduler.operations.operation.Operation` can be added using the :meth:`~.Schedule.add` method, allowing precise specification *when* to perform an operation using timing constraints. When adding an operation, it is not required to specify how to represent this :class:`quantify_scheduler.operations.operation.Operation` on all layers. Instead, this information can be added later during :ref:`compilation `. This allows the user to effortlessly mix the gate- and pulse-level descriptions as required for many (calibration) experiments. :param name: The name of the schedule :param repetitions: The amount of times the schedule will be repeated, by default 1 :param data: A dictionary containing a pre-existing schedule, by default None .. py:attribute:: schema_filename :value: 'schedule.json' .. py:method:: add_resources(resources_list: list) -> None Add wrapper for adding multiple resources. .. py:method:: add_resource(resource: quantify_scheduler.resources.Resource) -> None Add a resource such as a channel or qubit to the schedule. .. py:method:: add(operation: quantify_scheduler.operations.operation.Operation, rel_time: float = 0, ref_op: Schedulable | str | None = None, ref_pt: Literal[start, center, end] | None = None, ref_pt_new: Literal[start, center, end] | None = None, label: str = None) -> Schedulable Add an :class:`quantify_scheduler.operations.operation.Operation` to the schedule. :param operation: The operation to add to the schedule :param rel_time: relative time between the reference operation and the added operation. the time is the time between the "ref_pt" in the reference operation and "ref_pt_new" of the operation that is added. :param ref_op: reference schedulable. If set to :code:`None`, will default to the last added operation. :param ref_pt: reference point in reference operation must be one of :code:`"start"`, :code:`"center"`, :code:`"end"`, or :code:`None`; in case of :code:`None`, :func:`~quantify_scheduler.compilation.determine_absolute_timing` assumes :code:`"end"`. :param ref_pt_new: reference point in added operation must be one of :code:`"start"`, :code:`"center"`, :code:`"end"`, or :code:`None`; in case of :code:`None`, :func:`~quantify_scheduler.compilation.determine_absolute_timing` assumes :code:`"start"`. :param label: a unique string that can be used as an identifier when adding operations. if set to None, a random hash will be generated instead. :returns: returns the schedulable created on the schedule .. py:class:: Schedulable(name: str, operation_repr: str) Bases: :py:obj:`quantify_scheduler.json_utils.JSONSchemaValMixin`, :py:obj:`collections.UserDict` A representation of an element on a schedule. All elements on a schedule are schedulables. A schedulable contains all information regarding the timing of this element as well as the operation being executed by this element. This operation is currently represented by an operation ID. Schedulables can contain an arbitrary number of timing constraints to determine the timing. Multiple different constraints are currently resolved by delaying the element until after all timing constraints have been met, to aid compatibility. To specify an exact timing between two schedulables, please ensure to only specify exactly one timing constraint. :param name: The name of this schedulable, by which it can be referenced by other schedulables. Separate schedulables cannot share the same name :param operation_repr: The operation which is to be executed by this schedulable .. py:attribute:: schema_filename :value: 'schedulable.json' .. py:method:: add_timing_constraint(rel_time: float = 0, ref_schedulable: Schedulable | str | None = None, ref_pt: Literal[start, center, end] | None = None, ref_pt_new: Literal[start, center, end] | None = None) -> None Add timing constraint. A timing constraint constrains the operation in time by specifying the time (:code:`"rel_time"`) between a reference schedulable and the added schedulable. The time can be specified with respect to the "start", "center", or "end" of the operations. The reference schedulable (:code:`"ref_schedulable"`) is specified using its name property. See also :attr:`~.ScheduleBase.schedulables`. :param rel_time: relative time between the reference schedulable and the added schedulable. the time is the time between the "ref_pt" in the reference operation and "ref_pt_new" of the operation that is added. :param ref_schedulable: name of the reference schedulable. If set to :code:`None`, will default to the last added operation. :param ref_pt: reference point in reference operation must be one of :code:`"start"`, :code:`"center"`, :code:`"end"`, or :code:`None`; in case of :code:`None`, :meth:`~quantify_scheduler.compilation.determine_absolute_timing` assumes :code:`"end"`. :param ref_pt_new: reference point in added operation must be one of :code:`"start"`, :code:`"center"`, :code:`"end"`, or :code:`None`; in case of :code:`None`, :meth:`~quantify_scheduler.compilation.determine_absolute_timing` assumes :code:`"start"`. .. py:class:: CompiledSchedule(schedule: Schedule) Bases: :py:obj:`ScheduleBase` A schedule that contains compiled instructions ready for execution using the :class:`~.InstrumentCoordinator`. The :class:`CompiledSchedule` differs from a :class:`.Schedule` in that it is considered immutable (no new operations or resources can be added), and that it contains :attr:`~.compiled_instructions`. .. tip:: A :class:`~.CompiledSchedule` can be obtained by compiling a :class:`~.Schedule` using :meth:`~quantify_scheduler.backends.graph_compilation.QuantifyCompiler.compile`. .. py:property:: compiled_instructions :type: dict[str, quantify_scheduler.resources.Resource] A dictionary containing compiled instructions. The contents of this dictionary depend on the backend it was compiled for. However, we assume that the general format consists of a dictionary in which the keys are instrument names corresponding to components added to a :class:`~.InstrumentCoordinator`, and the values are the instructions for that component. These values typically contain a combination of sequence files, waveform definitions, and parameters to configure on the instrument. .. py:property:: hardware_timing_table :type: pandas.io.formats.style.Styler Return a timing table representing all operations at the Control-hardware layer. Note that this timing table is typically different from the `.timing_table` in that it contains more hardware specific information such as channels, clock cycles and samples and corrections for things such as gain. This hardware timing table is intended to provide a more This table is constructed based on the timing_table and modified during compilation in one of the hardware back ends and optionally added to the schedule. Not all back ends support this feature. .. py:property:: hardware_waveform_dict :type: dict[str, numpy.ndarray] Return a waveform dictionary representing all waveforms at the Control-hardware layer. Where the waveforms are represented as abstract waveforms in the Operations, this dictionary contains the numerical arrays that are uploaded to the hardware. This dictionary is constructed during compilation in the hardware back ends and optionally added to the schedule. Not all back ends support this feature. .. py:attribute:: schema_filename :value: 'schedule.json' .. py:method:: is_valid(object_to_be_validated: Any) -> bool :classmethod: Check if the contents of the object_to_be_validated are valid. Additionally checks if the object_to_be_validated is an instance of :class:`~.CompiledSchedule`. .. py:class:: AcquisitionMetadata A description of the shape and type of data that a schedule will return when executed. .. note:: The acquisition protocol, bin-mode and return types are assumed to be the same for all acquisitions in a schedule. .. py:attribute:: acq_protocol :type: str The acquisition protocol that is used for all acquisitions in the schedule. .. py:attribute:: bin_mode :type: quantify_scheduler.enums.BinMode How the data is stored in the bins indexed by acq_channel and acq_index. .. py:attribute:: acq_return_type :type: type The datatype returned by the individual acquisitions. .. py:attribute:: acq_indices :type: dict[int, list[int]] A dictionary containing the acquisition channel as key and a list of acquisition indices that are used for every channel. .. py:attribute:: repetitions :type: int How many times the acquisition was repeated on this specific sequencer.