Source code for quantify_scheduler.backends.qblox.visualization
# Repository: https://gitlab.com/quantify-os/quantify-scheduler
# Licensed according to the LICENCE file on the main branch
"""
Qblox Visualization Module.
This module, part of the Qblox backend system, is dedicated to creating and
managing visual and User Interface (UI) elements essential for representing
compiled instructions and other relevant data.
"""
from __future__ import annotations
import re
from contextlib import suppress
from dataclasses import asdict, is_dataclass
from typing import Any
import ipywidgets
import pandas as pd
from columnar import columnar
from IPython.display import display
from matplotlib import pyplot as plt
from matplotlib.ticker import MaxNLocator
[docs]
def _display_dict(settings: dict[str, Any]) -> None:
df = pd.DataFrame([settings]).T
df.columns = ["value"]
df.columns.name = "setting" # type: ignore
display(df)
[docs]
def _display_compiled_instructions( # noqa: PLR0915 (Too many branches)
data: dict[Any, Any], parent_tab_name: str | None = None
) -> ipywidgets.Tab | None:
"""
Display compiled instructions in a tabulated format.
This function creates an interactive table, rendering and displaying
compiled instructions along with other relevant data, allowing for a
structured and user-friendly representation.
In addition, it provides formatting specific for Qblox-specific sequencer
programs, waveforms, and settings.
.. admonition:: Note
This function is tailored for :attr:`~.CompiledSchedule.compiled_instructions`
but works with any nested dictionary.
.. admonition:: Example
.. jupyter-execute::
:hide-code:
from quantify_scheduler.backends import SerialCompiler
from quantify_scheduler.device_under_test.quantum_device import QuantumDevice
from quantify_scheduler.device_under_test.transmon_element import BasicTransmonElement
from quantify_scheduler.operations.gate_library import (
Measure,
Reset,
X,
Y,
)
from quantify_scheduler.schedules.schedule import Schedule
from quantify_scheduler.schemas.examples import utils
compiler = SerialCompiler("compiler")
q0 = BasicTransmonElement("q0")
q4 = BasicTransmonElement("q4")
for qubit in [q0, q4]:
qubit.rxy.amp180(0.115)
qubit.rxy.motzoi(0.1)
qubit.clock_freqs.f01(7.3e9)
qubit.clock_freqs.f12(7.0e9)
qubit.clock_freqs.readout(8.0e9)
qubit.measure.acq_delay(100e-9)
quantum_device = QuantumDevice(name="quantum_device")
quantum_device.add_element(q0)
quantum_device.add_element(q4)
device_config = quantum_device.generate_device_config()
hardware_config = utils.load_json_example_scheme(
"qblox_hardware_config_transmon.json"
)
quantum_device.hardware_config(hardware_config)
compilation_config = quantum_device.generate_compilation_config()
compiler = SerialCompiler("compiler")
compiler.quantum_device = quantum_device
.. jupyter-execute::
schedule = Schedule("demo compiled instructions")
schedule.add(Reset("q0", "q4"))
schedule.add(X("q0"))
schedule.add(Y("q4"))
schedule.add(Measure("q0", acq_channel=0, acq_protocol='ThresholdedAcquisition'))
schedule.add(Measure("q4", acq_channel=1, acq_protocol='ThresholdedAcquisition'))
comp_schedule = compiler.compile(schedule)
comp_schedule.compiled_instructions
Parameters
----------
data : dict
A dictionary containing the compiled instructions and related data. The
keys are strings representing tab names and the values are dictionaries
containing the respective instruction data.
parent_tab_name : str, optional
A string representing the name of the parent tab in the user interface.
If not specified, the function will use a default parent tab name.
Returns
-------
widgets.Tab or None
A Tab widget containing the structured representation of compiled
instructions if the input data is not empty, otherwise None.
"""
tab = ipywidgets.Tab()
children: list[ipywidgets.Tab | ipywidgets.Output | None] = []
titles: list[str] = []
non_dict_values = {}
for key, value in data.items():
# modules that have unused sequencers are unused and filtered out.
with suppress(AttributeError):
if value.sequencers == {}:
continue
tab_name = str(key)
child_tab = ipywidgets.Output()
if is_dataclass(value):
value = asdict(value) # noqa: PLW2901 (overriding for loop variable) # pyright: ignore
if isinstance(value, dict):
if parent_tab_name == "waveforms":
with child_tab:
tab_name = str(value["index"])
plt.plot(value["data"])
plt.xlabel("time [ns]")
plt.ylabel("amplitude")
plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
plt.show()
else:
child_tab = _display_compiled_instructions(value, parent_tab_name=str(key))
if child_tab:
children.append(child_tab)
titles.append(tab_name)
else:
non_dict_values[key] = value
if non_dict_values:
out = ipywidgets.Output()
with out:
if parent_tab_name == "sequence":
titles.append("program")
program = non_dict_values.get("program", "N/A")
pattern = r"^(?P<label>\S+)?\s*(?P<cmd>\S+)?\s*(?P<args>\S+)?\s*(?P<comment>#.*)?$"
matches = re.finditer(pattern, program, re.MULTILINE)
result = []
for match in matches:
row = [
match.group("label") or "",
match.group("cmd") or "",
match.group("args") or "",
match.group("comment") or "",
]
result.append(row)
print(columnar(result, headers=None, no_borders=True))
else:
tab_name = (
"settings"
if parent_tab_name and parent_tab_name.startswith("seq")
else "other values"
)
titles.append(tab_name)
_display_dict(non_dict_values)
children.append(out)
tab.children = children
for index, title in enumerate(titles):
tab_name = "other" if title == "generic" else str(title)
tab.set_title(index, tab_name)
if titles:
return tab