Source code for quantify_scheduler.compilation

# Repository: https://gitlab.com/quantify-os/quantify-scheduler
# Licensed according to the LICENCE file on the main branch
"""Compiler for the quantify_scheduler."""
from __future__ import annotations

import logging
from typing import Literal, Optional

from quantify_scheduler.backends.graph_compilation import (
    CompilationConfig,
)
from quantify_scheduler.json_utils import load_json_schema, validate_json
from quantify_scheduler.schedules.schedule import Schedule

[docs]logger = logging.getLogger(__name__)
[docs]def determine_absolute_timing( schedule: Schedule, time_unit: Literal[ "physical", "ideal", None ] = "physical", # should be included in CompilationConfig config: Optional[CompilationConfig] = None, ) -> Schedule: """ Determines the absolute timing of a schedule based on the timing constraints. This function determines absolute timings for every operation in the :attr:`~.ScheduleBase.schedulables`. It does this by: 1. iterating over all and elements in the :attr:`~.ScheduleBase.schedulables`. 2. determining the absolute time of the reference operation. 3. determining the start of the operation based on the `rel_time` and `duration` of operations. Parameters ---------- schedule The schedule for which to determine timings. config Compilation config for :class:`~quantify_scheduler.backends.graph_compilation.QuantifyCompiler`, which is currently not used in this compilation step. time_unit Whether to use physical units to determine the absolute time or ideal time. When :code:`time_unit == "physical"` the duration attribute is used. When :code:`time_unit == "ideal"` the duration attribute is ignored and treated as if it is :code:`1`. When :code:`time_unit == None` it will revert to :code:`"physical"`. Returns ------- : a new schedule object where the absolute time for each operation has been determined. """ if len(schedule.schedulables) == 0: raise ValueError(f"schedule '{schedule.name}' contains no schedulables.") if time_unit is None: time_unit = "physical" valid_time_units = ("physical", "ideal") if time_unit not in valid_time_units: raise ValueError( f"Undefined time_unit '{time_unit}'! Must be one of {valid_time_units}" ) # iterate over the objects in the schedule. last_schedulable = next(iter(schedule.schedulables.values())) last_op = schedule.operations[last_schedulable["operation_repr"]] last_schedulable["abs_time"] = 0 for schedulable in list(schedule.data["schedulables"].values())[1:]: curr_op = schedule.operations[schedulable["operation_repr"]] if len(schedulable.data["timing_constraints"]) == 0: schedulable.add_timing_constraint(ref_schedulable=last_schedulable) for t_constr in schedulable.data["timing_constraints"]: if t_constr["ref_schedulable"] is None: ref_schedulable = last_schedulable ref_op = last_op else: # this assumes the reference op exists. This is ensured in schedule.add ref_schedulable = schedule.schedulables[ str(t_constr["ref_schedulable"]) ] ref_op = schedule.operations[ref_schedulable["operation_repr"]] # duration = 1 is useful when e.g., drawing a circuit diagram. duration_ref_op = ref_op.duration if time_unit == "physical" else 1 if t_constr["ref_pt"] == "start": t0 = ref_schedulable["abs_time"] elif t_constr["ref_pt"] == "center": t0 = ref_schedulable["abs_time"] + duration_ref_op / 2 elif t_constr["ref_pt"] == "end": t0 = ref_schedulable["abs_time"] + duration_ref_op else: raise NotImplementedError( f'Timing "{ref_schedulable["abs_time"]}" not supported by backend.' ) duration_new_op = curr_op.duration if time_unit == "physical" else 1 if t_constr["ref_pt_new"] == "start": abs_time = t0 + t_constr["rel_time"] elif t_constr["ref_pt_new"] == "center": abs_time = t0 + t_constr["rel_time"] - duration_new_op / 2 elif t_constr["ref_pt_new"] == "end": abs_time = t0 + t_constr["rel_time"] - duration_new_op if "abs_time" not in schedulable or abs_time > schedulable["abs_time"]: schedulable["abs_time"] = abs_time # update last_constraint and operation for next iteration of the loop last_schedulable = schedulable last_op = curr_op return schedule
[docs]def validate_config(config: dict, scheme_fn: str) -> bool: """ Validate a configuration using a schema. Parameters ---------- config The configuration to validate scheme_fn The name of a json schema in the quantify_scheduler.schemas folder. Returns ---------- : True if valid """ scheme = load_json_schema(__file__, scheme_fn) validate_json(config, scheme) return True