graph_compilation#
Graph compilation backend of quantify-scheduler.
Module Contents#
Classes#
Datastructure specifying the structure of a simple compiler pass config. |
|
Information required to compile an individual operation to the quantum-device layer. |
|
Information required to compile a schedule to the quantum-device layer. |
|
Base class for a compilation config. |
|
A node representing a compiler pass. |
|
A node representing a single compilation pass. |
|
A compiler for quantify |
|
A compiler that executes compilation passes sequentially. |
|
A compilation config for a simple serial compiler. |
- exception CompilationError[source]#
Bases:
RuntimeError
Custom exception class for failures in compilation of quantify schedules.
- class SimpleNodeConfig(/, **data: Any)[source]#
Bases:
quantify_scheduler.structure.model.DataStructure
Datastructure specifying the structure of a simple compiler pass config.
See also
SimpleNode
.- compilation_func: Callable[[quantify_scheduler.schedules.schedule.Schedule, Any], quantify_scheduler.schedules.schedule.Schedule][source]#
The function to perform the compilation pass as an importable string (e.g., “package_name.my_module.function_name”).
- _import_compilation_func_if_str(fun: Callable[[quantify_scheduler.schedules.schedule.Schedule, Any], quantify_scheduler.schedules.schedule.Schedule]) Callable[[quantify_scheduler.schedules.schedule.Schedule, Any], quantify_scheduler.schedules.schedule.Schedule] [source]#
- class OperationCompilationConfig(/, **data: Any)[source]#
Bases:
quantify_scheduler.structure.model.DataStructure
Information required to compile an individual operation to the quantum-device layer.
From a point of view of Compilation this information is needed to convert an operation defined on a quantum-circuit layer to an operation defined on a quantum-device layer.
- factory_func: Callable[Ellipsis, quantify_scheduler.operations.operation.Operation | quantify_scheduler.schedules.schedule.Schedule][source]#
A callable designating a factory function used to create the representation of the operation at the quantum-device level.
- factory_kwargs: Dict[str, Any][source]#
A dictionary containing the keyword arguments and corresponding values to use when creating the operation by evaluating the factory function.
- gate_info_factory_kwargs: List[str] | None = None[source]#
A list of keyword arguments of the factory function for which the value must be retrieved from the
gate_info
of the operation.
- _import_factory_func_if_str(fun: str | Callable[Ellipsis, quantify_scheduler.operations.operation.Operation]) Callable[Ellipsis, quantify_scheduler.operations.operation.Operation] [source]#
- class DeviceCompilationConfig(/, **data: Any)[source]#
Bases:
quantify_scheduler.structure.model.DataStructure
Information required to compile a schedule to the quantum-device layer.
From a point of view of Compilation this information is needed to convert a schedule defined on a quantum-circuit layer to a schedule defined on a quantum-device layer.
Examples
The DeviceCompilationConfig is structured such that it should allow the specification of the circuit-to-device compilation for many different qubit platforms. Here we show a basic configuration for a two-transmon quantum device. In this example, the DeviceCompilationConfig is created by parsing a dictionary containing the relevant information.
Important
Although it is possible to manually create a configuration using dictionaries, this is not recommended. The
QuantumDevice
is responsible for managing and generating configuration files.import pprint from quantify_scheduler.backends.graph_compilation import ( DeviceCompilationConfig ) from quantify_scheduler.schemas.examples.device_example_cfgs import ( example_transmon_cfg ) pprint.pprint(example_transmon_cfg)
{'clocks': {'q0.01': 6020000000.0, 'q0.ro': 7040000000.0, 'q1.01': 5020000000.0, 'q1.ro': 6900000000.0}, 'compilation_passes': [{'compilation_func': 'quantify_scheduler.backends.circuit_to_device.compile_circuit_to_device_with_config_validation', 'name': 'circuit_to_device'}], 'edges': {'q0_q1': {'CZ': {'factory_func': 'quantify_scheduler.operations.pulse_factories.composite_square_pulse', 'factory_kwargs': {'square_amp': 0.5, 'square_clock': 'cl0.baseband', 'square_duration': 2e-08, 'square_port': 'q0:fl', 'virt_z_child_qubit_clock': 'q1.01', 'virt_z_child_qubit_phase': 63, 'virt_z_parent_qubit_clock': 'q0.01', 'virt_z_parent_qubit_phase': 44}}}}, 'elements': {'q0': {'H': {'factory_func': 'quantify_scheduler.operations.composite_factories.hadamard_as_y90z', 'factory_kwargs': {'qubit': 'q0'}}, 'Rxy': {'factory_func': 'quantify_scheduler.operations.pulse_factories.rxy_drag_pulse', 'factory_kwargs': {'amp180': 0.32, 'clock': 'q0.01', 'duration': 2e-08, 'motzoi': 0.45, 'port': 'q0:mw'}, 'gate_info_factory_kwargs': ['theta', 'phi']}, 'Rz': {'factory_func': 'quantify_scheduler.operations.pulse_factories.phase_shift', 'factory_kwargs': {'clock': 'q0.01'}, 'gate_info_factory_kwargs': ['theta']}, 'measure': {'factory_func': 'quantify_scheduler.operations.measurement_factories.dispersive_measurement_transmon', 'factory_kwargs': {'acq_channel': 0, 'acq_delay': 1.2e-07, 'acq_duration': 3e-07, 'acq_rotation': 0, 'acq_threshold': 0, 'clock': 'q0.ro', 'freq': None, 'port': 'q0:res', 'pulse_amp': 0.25, 'pulse_duration': 1.6e-07, 'pulse_type': 'SquarePulse'}, 'gate_info_factory_kwargs': ['acq_channel_override', 'acq_index', 'bin_mode', 'acq_protocol']}, 'reset': {'factory_func': 'quantify_scheduler.operations.pulse_library.IdlePulse', 'factory_kwargs': {'duration': 0.0002}}}, 'q1': {'Rxy': {'factory_func': 'quantify_scheduler.operations.pulse_factories.rxy_drag_pulse', 'factory_kwargs': {'amp180': 0.4, 'clock': 'q1.01', 'duration': 2e-08, 'motzoi': 0.25, 'port': 'q1:mw'}, 'gate_info_factory_kwargs': ['theta', 'phi']}, 'Rz': {'factory_func': 'quantify_scheduler.operations.pulse_factories.phase_shift', 'factory_kwargs': {'clock': 'q1.01'}, 'gate_info_factory_kwargs': ['theta']}, 'measure': {'factory_func': 'quantify_scheduler.operations.measurement_factories.dispersive_measurement_transmon', 'factory_kwargs': {'acq_channel': 1, 'acq_delay': 1.2e-07, 'acq_duration': 3e-07, 'acq_rotation': 0, 'acq_threshold': 0, 'clock': 'q1.ro', 'freq': None, 'port': 'q1:res', 'pulse_amp': 0.21, 'pulse_duration': 1.6e-07, 'pulse_type': 'SquarePulse'}, 'gate_info_factory_kwargs': ['acq_channel_override', 'acq_index', 'bin_mode', 'acq_protocol']}, 'reset': {'factory_func': 'quantify_scheduler.operations.pulse_library.IdlePulse', 'factory_kwargs': {'duration': 0.0002}}}}}
The dictionary can be parsed using the
model_validate
method.device_cfg = DeviceCompilationConfig.model_validate(example_transmon_cfg) device_cfg
DeviceCompilationConfig(clocks={'q0.01': 6020000000.0, 'q0.ro': 7040000000.0, 'q1.01': 5020000000.0, 'q1.ro': 6900000000.0}, elements={'q0': {'reset': OperationCompilationConfig(factory_func=<class 'quantify_scheduler.operations.pulse_library.IdlePulse'>, factory_kwargs={'duration': 0.0002}, gate_info_factory_kwargs=None), 'Rxy': OperationCompilationConfig(factory_func=<function rxy_drag_pulse at 0x7b02e2dcdee0>, factory_kwargs={'amp180': 0.32, 'motzoi': 0.45, 'port': 'q0:mw', 'clock': 'q0.01', 'duration': 2e-08}, gate_info_factory_kwargs=['theta', 'phi']), 'Rz': OperationCompilationConfig(factory_func=<function phase_shift at 0x7b02b9607ee0>, factory_kwargs={'clock': 'q0.01'}, gate_info_factory_kwargs=['theta']), 'H': OperationCompilationConfig(factory_func=<function hadamard_as_y90z at 0x7b02b93f7b80>, factory_kwargs={'qubit': 'q0'}, gate_info_factory_kwargs=None), 'measure': OperationCompilationConfig(factory_func=<function dispersive_measurement_transmon at 0x7b02b93f7ee0>, factory_kwargs={'port': 'q0:res', 'clock': 'q0.ro', 'pulse_type': 'SquarePulse', 'pulse_amp': 0.25, 'pulse_duration': 1.6e-07, 'acq_delay': 1.2e-07, 'acq_duration': 3e-07, 'acq_channel': 0, 'acq_rotation': 0, 'acq_threshold': 0, 'freq': None}, gate_info_factory_kwargs=['acq_channel_override', 'acq_index', 'bin_mode', 'acq_protocol'])}, 'q1': {'reset': OperationCompilationConfig(factory_func=<class 'quantify_scheduler.operations.pulse_library.IdlePulse'>, factory_kwargs={'duration': 0.0002}, gate_info_factory_kwargs=None), 'Rxy': OperationCompilationConfig(factory_func=<function rxy_drag_pulse at 0x7b02e2dcdee0>, factory_kwargs={'amp180': 0.4, 'motzoi': 0.25, 'port': 'q1:mw', 'clock': 'q1.01', 'duration': 2e-08}, gate_info_factory_kwargs=['theta', 'phi']), 'Rz': OperationCompilationConfig(factory_func=<function phase_shift at 0x7b02b9607ee0>, factory_kwargs={'clock': 'q1.01'}, gate_info_factory_kwargs=['theta']), 'measure': OperationCompilationConfig(factory_func=<function dispersive_measurement_transmon at 0x7b02b93f7ee0>, factory_kwargs={'port': 'q1:res', 'clock': 'q1.ro', 'pulse_type': 'SquarePulse', 'pulse_amp': 0.21, 'pulse_duration': 1.6e-07, 'acq_delay': 1.2e-07, 'acq_duration': 3e-07, 'acq_channel': 1, 'acq_rotation': 0, 'acq_threshold': 0, 'freq': None}, gate_info_factory_kwargs=['acq_channel_override', 'acq_index', 'bin_mode', 'acq_protocol'])}}, edges={'q0_q1': {'CZ': OperationCompilationConfig(factory_func=<function composite_square_pulse at 0x7b02b93f7670>, factory_kwargs={'square_port': 'q0:fl', 'square_clock': 'cl0.baseband', 'square_amp': 0.5, 'square_duration': 2e-08, 'virt_z_parent_qubit_phase': 44, 'virt_z_parent_qubit_clock': 'q0.01', 'virt_z_child_qubit_phase': 63, 'virt_z_child_qubit_clock': 'q1.01'}, gate_info_factory_kwargs=None)}}, scheduling_strategy='asap', compilation_passes=[SimpleNodeConfig(name='circuit_to_device', compilation_func=<function compile_circuit_to_device_with_config_validation at 0x7b02b93f83a0>)])
- clocks: Dict[str, float][source]#
A dictionary specifying the clock frequencies available on the device e.g.,
{"q0.01": 6.123e9}
.
- elements: Dict[str, Dict[str, OperationCompilationConfig]][source]#
A dictionary specifying the elements on the device, what operations can be applied to them and how to compile these.
- edges: Dict[str, Dict[str, OperationCompilationConfig]][source]#
A dictionary specifying the edges, links between elements on the device to which operations can be applied, and the operations that can be applied to them and how to compile these.
- scheduling_strategy: Literal['asap', 'alap'] = 'asap'[source]#
The scheduling strategy used when determining the absolute timing of each operation of the schedule.
- compilation_passes: List[SimpleNodeConfig][source]#
The list of compilation nodes that should be called in succession to compile a schedule to the quantum-device layer.
- class CompilationConfig(/, **data: Any)[source]#
Bases:
quantify_scheduler.structure.model.DataStructure
Base class for a compilation config.
Subclassing is generally required to create useful compilation configs, here extra fields can be defined.
- version: str = 'v0.6'[source]#
The version of the
CompilationConfig
to facilitate backwards compatibility.
- keep_original_schedule: bool = True[source]#
If
True
, the compiler will not modify the schedule argument. IfFalse
, the compilation modifies the schedule, thereby making the original schedule unusable for further usage; this improves compilation time. Warning: ifFalse
, the returned schedule references objects from the original schedule, please refrain from modifying the original schedule after compilation in this case!
- backend: Type[QuantifyCompiler][source]#
A reference string to the
QuantifyCompiler
class used in the compilation.
- device_compilation_config: DeviceCompilationConfig | None = None[source]#
The
DeviceCompilationConfig
used in the compilation from the quantum-circuit layer to the quantum-device layer.
- hardware_compilation_config: quantify_scheduler.backends.types.common.HardwareCompilationConfig | None = None[source]#
The
HardwareCompilationConfig
used in the compilation from the quantum-device layer to the control-hardware layer.
- debug_mode: bool = False[source]#
Debug mode can modify the compilation process, so that debugging of the compilation process is easier.
- _import_backend_if_str(class_: Type[QuantifyCompiler] | str) Type[QuantifyCompiler] [source]#
- class CompilationNode(name: str)[source]#
A node representing a compiler pass.
Note
To compile, the
compile()
method should be used.- Parameters:
name – The name of the node. Should be unique if it is added to a (larger) compilation graph.
- abstract _compilation_func(schedule: quantify_scheduler.schedules.schedule.Schedule | quantify_scheduler.structure.model.DataStructure, config: quantify_scheduler.structure.model.DataStructure) quantify_scheduler.schedules.schedule.Schedule | quantify_scheduler.structure.model.DataStructure [source]#
Private compilation method of this CompilationNode.
It should be completely stateless whenever inheriting from the CompilationNode, this is the object that should be modified.
- compile(schedule: quantify_scheduler.schedules.schedule.Schedule | quantify_scheduler.structure.model.DataStructure, config: quantify_scheduler.structure.model.DataStructure) quantify_scheduler.schedules.schedule.Schedule | quantify_scheduler.structure.model.DataStructure [source]#
Execute a compilation pass.
This method takes a
Schedule
and returns a new (updated)Schedule
using the information provided in the config.
- class SimpleNode(name: str, compilation_func: Callable)[source]#
Bases:
CompilationNode
A node representing a single compilation pass.
Note
To compile, the
compile()
method should be used.- Parameters:
name – The name of the node. Should be unique if it is added to a (larger) compilation graph.
compilation_func – A Callable that will be wrapped in this object. A compilation function should take the intermediate representation (commonly
Schedule
) and a config as inputs and returns a new (modified) intermediate representation.
- _compilation_func(schedule: quantify_scheduler.schedules.schedule.Schedule, config: quantify_scheduler.structure.model.DataStructure | dict) quantify_scheduler.schedules.schedule.Schedule [source]#
Private compilation method of this CompilationNode.
It should be completely stateless whenever inheriting from the CompilationNode, this is the object that should be modified.
- class QuantifyCompiler(name, quantum_device: quantify_scheduler.device_under_test.quantum_device.QuantumDevice | None = None)[source]#
Bases:
CompilationNode
A compiler for quantify
Schedule
s.The compiler defines a directed acyclic graph containing
CompilationNode
s. In this graph, nodes represent modular compilation passes.- Parameters:
name – name of the compiler instance
quantum_device – quantum_device from which a
CompilationConfig
will be generated if None is provided for the compile step
- _task_graph: networkx.DiGraph = None[source]#
- compile(schedule: quantify_scheduler.schedules.schedule.Schedule, config: CompilationConfig | None = None) quantify_scheduler.schedules.schedule.CompiledSchedule [source]#
Compile a
Schedule
using the information provided in the config.- Parameters:
schedule – the schedule to compile.
config – describing the information required to compile the schedule. If not specified, self.quantum_device will be used to generate the config.
- Returns:
a compiled schedule containing the compiled instructions suitable for execution on a (hardware) backend.
- Return type:
- property input_node[source]#
- Node designated as the default input for compilation.
If not specified will return None.
- property output_node[source]#
- Node designated as the default output for compilation.
If not specified will return None.
- abstract construct_graph(config: CompilationConfig)[source]#
Construct the compilation graph based on a provided config.
- draw(ax: matplotlib.axes.Axes = None, figsize: Tuple[float, float] = (20, 10), **options) matplotlib.axes.Axes [source]#
Draws the graph defined by this backend using matplotlib.
Will attempt to position the nodes using the “dot” algorithm for directed acyclic graphs from graphviz if available. See https://pygraphviz.github.io/documentation/stable/install.html for installation instructions of pygraphviz and graphviz.
If not available will use the Kamada Kawai positioning algorithm.
- Parameters:
ax – Matplotlib axis to plot the figure on
figsize – Optional figure size, defaults to something slightly larger that fits the size of the nodes.
options – optional keyword arguments that are passed to
networkx.draw_networkx
.
- class SerialCompiler(name, quantum_device: quantify_scheduler.device_under_test.quantum_device.QuantumDevice | None = None)[source]#
Bases:
QuantifyCompiler
A compiler that executes compilation passes sequentially.
- construct_graph(config: SerialCompilationConfig)[source]#
Construct the compilation graph based on a provided config.
For a serial backend, it is just a list of compilation passes.
- _compilation_func(schedule: quantify_scheduler.schedules.schedule.Schedule, config: SerialCompilationConfig) quantify_scheduler.schedules.schedule.CompiledSchedule [source]#
Compile a schedule using the backend and the information provided in the config.
- Parameters:
schedule – The schedule to compile.
config – A dictionary containing the information needed to compile the schedule. Nodes in this compiler specify what key they need information from in this dictionary.
- class SerialCompilationConfig(/, **data: Any)[source]#
Bases:
CompilationConfig
A compilation config for a simple serial compiler.
Specifies compilation as a list of compilation passes.
- backend: Type[SerialCompiler][source]#
A reference string to the
QuantifyCompiler
class used in the compilation.
- _import_backend_if_str(class_: Type[SerialCompiler] | str) Type[SerialCompiler] [source]#