From 39447877d3ffefb814f642a1af7914f199208b2d Mon Sep 17 00:00:00 2001 From: Andrea Pasquale Date: Fri, 15 Nov 2024 16:36:22 +0100 Subject: [PATCH 1/9] feat: script to generate calibration.json --- generate_calibration.py | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 generate_calibration.py diff --git a/generate_calibration.py b/generate_calibration.py new file mode 100644 index 00000000..5fe56f00 --- /dev/null +++ b/generate_calibration.py @@ -0,0 +1,64 @@ +import argparse +import json +from pathlib import Path + + + +def single_qubits(o: dict) -> dict: + return { q: { + "resonator": { + "bare_frequency": k["bare_resonator_frequency"], + "dressed_frequency": k["readout_frequency"], + }, + "qubit": { + "frequency_01": k["drive_frequency"], + "sweetspot": k["sweetspot"], + }, + "readout":{ + "fidelity": k["readout_fidelity"], + "ground_state": k["mean_gnd_states"], + "excited_state": k["mean_exc_states"], + }, + "t1": [k["T1"], None], + "t2": [k["T2"], None], + "t2_spin_echo": [k["T2_spin_echo"], None], + "rb_fidelity": [k["gate_fidelity"], None], + } for q, k in o.items()} + + +def two_qubits(o:dict) -> dict: + return {qq :{ + "rb_fidelity": [k["gate_fidelity"], None], + "cz_fidelity": [k["cz_fidelity"], None], + } for qq, k in o.items()} + + +def upgrade(o: dict) -> dict: + return { + "single_qubits": single_qubits(o["characterization"]["single_qubit"] + ), + "two_qubits": two_qubits(o["characterization"]["two_qubit"]), + } + + +def convert(path: Path): + params = json.loads(path.read_text()) + new = upgrade(params) + path.with_stem("calibration_new").write_text(json.dumps(new, indent=4)) + + +def parse(): + parser = argparse.ArgumentParser() + parser.add_argument("path", nargs="*", type=Path) + return parser.parse_args() + + +def main(): + args = parse() + + for p in args.path: + convert(p) + + +if __name__ == "__main__": + main() From 6793e74e36b7a4a65e29e65a6ba269f925c6f9cc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:40:52 +0000 Subject: [PATCH 2/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- generate_calibration.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/generate_calibration.py b/generate_calibration.py index 5fe56f00..77aa04d3 100644 --- a/generate_calibration.py +++ b/generate_calibration.py @@ -3,18 +3,18 @@ from pathlib import Path - def single_qubits(o: dict) -> dict: - return { q: { + return { + q: { "resonator": { "bare_frequency": k["bare_resonator_frequency"], "dressed_frequency": k["readout_frequency"], - }, + }, "qubit": { "frequency_01": k["drive_frequency"], "sweetspot": k["sweetspot"], }, - "readout":{ + "readout": { "fidelity": k["readout_fidelity"], "ground_state": k["mean_gnd_states"], "excited_state": k["mean_exc_states"], @@ -23,20 +23,24 @@ def single_qubits(o: dict) -> dict: "t2": [k["T2"], None], "t2_spin_echo": [k["T2_spin_echo"], None], "rb_fidelity": [k["gate_fidelity"], None], - } for q, k in o.items()} + } + for q, k in o.items() + } -def two_qubits(o:dict) -> dict: - return {qq :{ - "rb_fidelity": [k["gate_fidelity"], None], - "cz_fidelity": [k["cz_fidelity"], None], - } for qq, k in o.items()} +def two_qubits(o: dict) -> dict: + return { + qq: { + "rb_fidelity": [k["gate_fidelity"], None], + "cz_fidelity": [k["cz_fidelity"], None], + } + for qq, k in o.items() + } def upgrade(o: dict) -> dict: return { - "single_qubits": single_qubits(o["characterization"]["single_qubit"] - ), + "single_qubits": single_qubits(o["characterization"]["single_qubit"]), "two_qubits": two_qubits(o["characterization"]["two_qubit"]), } From dd8e963cee3eee7acab24ad4b03823e57b53de8b Mon Sep 17 00:00:00 2001 From: Andrea Pasquale Date: Fri, 15 Nov 2024 17:57:15 +0100 Subject: [PATCH 3/9] chore: Unify scripts --- convert.py | 41 +++++++++++++++++++++++-- generate_calibration.py | 68 ----------------------------------------- 2 files changed, 39 insertions(+), 70 deletions(-) delete mode 100644 generate_calibration.py diff --git a/convert.py b/convert.py index 5aaac7a5..1165f01a 100644 --- a/convert.py +++ b/convert.py @@ -1,9 +1,10 @@ +"""Converts parameters.json to parameters.json and calibration.json +""" import argparse import ast import json from pathlib import Path from typing import Optional - from pydantic import TypeAdapter from qibolab._core.serialize import NdArray @@ -180,11 +181,48 @@ def upgrade(o: dict) -> dict: "native_gates": natives(o["native_gates"]), } +def single_qubits_cal(o: dict) -> dict: + return { q: { + "resonator": { + "bare_frequency": k["bare_resonator_frequency"], + "dressed_frequency": k["readout_frequency"], + }, + "qubit": { + "frequency_01": k["drive_frequency"], + "sweetspot": k["sweetspot"], + }, + "readout":{ + "fidelity": k["readout_fidelity"], + "ground_state": k["mean_gnd_states"], + "excited_state": k["mean_exc_states"], + }, + "t1": [k["T1"], None], + "t2": [k["T2"], None], + "t2_spin_echo": [k["T2_spin_echo"], None], + "rb_fidelity": [k["gate_fidelity"], None], + } for q, k in o.items()} + + +def two_qubits_cal(o:dict) -> dict: + return {qq :{ + "rb_fidelity": [k["gate_fidelity"], None], + "cz_fidelity": [k["cz_fidelity"], None], + } for qq, k in o.items()} + + +def upgrade_cal(o: dict) -> dict: + return { + "single_qubits": single_qubits_cal(o["characterization"]["single_qubit"] + ), + "two_qubits": two_qubits_cal(o["characterization"]["two_qubit"]), + } def convert(path: Path): params = json.loads(path.read_text()) new = upgrade(params) + cal = upgrade_cal(params) path.with_stem(path.stem + "-new").write_text(json.dumps(new, indent=4)) + path.with_stem("calibration").write_text(json.dumps(new, indent=4)) def parse(): @@ -195,7 +233,6 @@ def parse(): def main(): args = parse() - for p in args.path: convert(p) diff --git a/generate_calibration.py b/generate_calibration.py deleted file mode 100644 index 77aa04d3..00000000 --- a/generate_calibration.py +++ /dev/null @@ -1,68 +0,0 @@ -import argparse -import json -from pathlib import Path - - -def single_qubits(o: dict) -> dict: - return { - q: { - "resonator": { - "bare_frequency": k["bare_resonator_frequency"], - "dressed_frequency": k["readout_frequency"], - }, - "qubit": { - "frequency_01": k["drive_frequency"], - "sweetspot": k["sweetspot"], - }, - "readout": { - "fidelity": k["readout_fidelity"], - "ground_state": k["mean_gnd_states"], - "excited_state": k["mean_exc_states"], - }, - "t1": [k["T1"], None], - "t2": [k["T2"], None], - "t2_spin_echo": [k["T2_spin_echo"], None], - "rb_fidelity": [k["gate_fidelity"], None], - } - for q, k in o.items() - } - - -def two_qubits(o: dict) -> dict: - return { - qq: { - "rb_fidelity": [k["gate_fidelity"], None], - "cz_fidelity": [k["cz_fidelity"], None], - } - for qq, k in o.items() - } - - -def upgrade(o: dict) -> dict: - return { - "single_qubits": single_qubits(o["characterization"]["single_qubit"]), - "two_qubits": two_qubits(o["characterization"]["two_qubit"]), - } - - -def convert(path: Path): - params = json.loads(path.read_text()) - new = upgrade(params) - path.with_stem("calibration_new").write_text(json.dumps(new, indent=4)) - - -def parse(): - parser = argparse.ArgumentParser() - parser.add_argument("path", nargs="*", type=Path) - return parser.parse_args() - - -def main(): - args = parse() - - for p in args.path: - convert(p) - - -if __name__ == "__main__": - main() From 554c8d906cf4a7d03ff482f413a6ff5faca841eb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:58:31 +0000 Subject: [PATCH 4/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- convert.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/convert.py b/convert.py index 1165f01a..23f31d09 100644 --- a/convert.py +++ b/convert.py @@ -1,10 +1,12 @@ """Converts parameters.json to parameters.json and calibration.json """ + import argparse import ast import json from pathlib import Path from typing import Optional + from pydantic import TypeAdapter from qibolab._core.serialize import NdArray @@ -181,17 +183,19 @@ def upgrade(o: dict) -> dict: "native_gates": natives(o["native_gates"]), } + def single_qubits_cal(o: dict) -> dict: - return { q: { + return { + q: { "resonator": { "bare_frequency": k["bare_resonator_frequency"], "dressed_frequency": k["readout_frequency"], - }, + }, "qubit": { "frequency_01": k["drive_frequency"], "sweetspot": k["sweetspot"], }, - "readout":{ + "readout": { "fidelity": k["readout_fidelity"], "ground_state": k["mean_gnd_states"], "excited_state": k["mean_exc_states"], @@ -200,23 +204,28 @@ def single_qubits_cal(o: dict) -> dict: "t2": [k["T2"], None], "t2_spin_echo": [k["T2_spin_echo"], None], "rb_fidelity": [k["gate_fidelity"], None], - } for q, k in o.items()} + } + for q, k in o.items() + } -def two_qubits_cal(o:dict) -> dict: - return {qq :{ - "rb_fidelity": [k["gate_fidelity"], None], - "cz_fidelity": [k["cz_fidelity"], None], - } for qq, k in o.items()} +def two_qubits_cal(o: dict) -> dict: + return { + qq: { + "rb_fidelity": [k["gate_fidelity"], None], + "cz_fidelity": [k["cz_fidelity"], None], + } + for qq, k in o.items() + } def upgrade_cal(o: dict) -> dict: return { - "single_qubits": single_qubits_cal(o["characterization"]["single_qubit"] - ), + "single_qubits": single_qubits_cal(o["characterization"]["single_qubit"]), "two_qubits": two_qubits_cal(o["characterization"]["two_qubit"]), } + def convert(path: Path): params = json.loads(path.read_text()) new = upgrade(params) From a97d9dc2ea670533968a3880f48af8e4454936d5 Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:16:25 +0400 Subject: [PATCH 5/9] fix: dump calibration file instead of dumping parameters-new twice --- convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/convert.py b/convert.py index 23f31d09..3bf7d9d1 100644 --- a/convert.py +++ b/convert.py @@ -231,7 +231,7 @@ def convert(path: Path): new = upgrade(params) cal = upgrade_cal(params) path.with_stem(path.stem + "-new").write_text(json.dumps(new, indent=4)) - path.with_stem("calibration").write_text(json.dumps(new, indent=4)) + path.with_stem("calibration").write_text(json.dumps(cal, indent=4)) def parse(): From 7f3290e48b1a5fec2f53a99cd005bc9bae1cef59 Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:58:15 +0400 Subject: [PATCH 6/9] feat: update convert.py script to generate QM specific configs --- convert.py | 75 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/convert.py b/convert.py index 3bf7d9d1..b3b9563b 100644 --- a/convert.py +++ b/convert.py @@ -4,6 +4,7 @@ import argparse import ast import json +from dataclasses import dataclass from pathlib import Path from typing import Optional @@ -18,10 +19,51 @@ def channel_from_pulse(pulse: dict) -> dict: return {"kind": "iq", "frequency": pulse["frequency"]} +@dataclass +class QmConnection: + instrument: str + port: str + output_mode: str = "triggered" + + +def qm_configs(conf: dict, instruments: dict, instrument_channels: dict) -> dict: + for channel, conn in instrument_channels.items(): + connection = QmConnection(**conn) + settings = instruments.get(connection.instrument, {}).get(connection.port, {}) + if channel in conf: + kind = conf[channel]["kind"] + if kind == "acquisition": + conf[channel].update( + {"kind": "qm-acquisition", "gain": settings.get("gain", 0)} + ) + elif kind == "dc": + conf[channel].update( + { + "kind": "opx-output", + "filter": settings.get("filter", {}), + "output_mode": settings.get("output_mode", "direct"), + } + ) + else: + raise NotImplementedError + else: + conf[channel] = { + "kind": "octave-oscillator", + "frequency": settings["lo_frequency"], + "power": settings["gain"], + "output_mode": connection.output_mode, + } + return conf + + def configs( - instruments: dict, single: dict, couplers: dict, characterization: dict + instruments: dict, + single: dict, + couplers: dict, + characterization: dict, + connections: Optional[dict] = None, ) -> dict: - return ( + conf = ( { f"{k}/bounds": (v["bounds"] | {"kind": "bounds"}) for k, v in instruments.items() @@ -57,6 +99,12 @@ def configs( for id, char in characterization.get("coupler", {}).items() } ) + if connections is not None: + if connections["kind"] == "qm": + conf = qm_configs(conf, instruments, connections["channels"]) + else: + raise NotImplementedError + return conf def channel(qubit: str, type_: str, gate: Optional[str] = None) -> str: @@ -171,7 +219,7 @@ def natives(o: dict) -> dict: } -def upgrade(o: dict) -> dict: +def upgrade(o: dict, connections: Optional[dict] = None) -> dict: return { "settings": o["settings"], "configs": configs( @@ -179,6 +227,7 @@ def upgrade(o: dict) -> dict: o["native_gates"]["single_qubit"], o["native_gates"].get("coupler", {}), o["characterization"], + connections, ), "native_gates": natives(o["native_gates"]), } @@ -226,9 +275,14 @@ def upgrade_cal(o: dict) -> dict: } -def convert(path: Path): +def convert(path: Path, connections_path: Optional[Path] = None): params = json.loads(path.read_text()) - new = upgrade(params) + connections = ( + json.loads(connections_path.read_text()) + if connections_path is not None + else None + ) + new = upgrade(params, connections) cal = upgrade_cal(params) path.with_stem(path.stem + "-new").write_text(json.dumps(new, indent=4)) path.with_stem("calibration").write_text(json.dumps(cal, indent=4)) @@ -237,13 +291,20 @@ def convert(path: Path): def parse(): parser = argparse.ArgumentParser() parser.add_argument("path", nargs="*", type=Path) + parser.add_argument("--connections", nargs="*", default=None, type=Path) return parser.parse_args() def main(): args = parse() - for p in args.path: - convert(p) + connections = args.connections + if connections is not None: + assert len(args.path) == len(connections) + else: + connections = len(args.path) * [None] + + for p, c in zip(args.path, connections): + convert(p, c) if __name__ == "__main__": From 9bc29f195971a5e225d2a51c44a874b3c4f27f6f Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Tue, 26 Nov 2024 12:58:42 +0400 Subject: [PATCH 7/9] chore: add connections files to avoid dependency on qibolab --- qw11q/connections.json | 189 +++++++++++++++++++++++++++++++++ qw5q_platinum/connections.json | 70 ++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 qw11q/connections.json create mode 100644 qw5q_platinum/connections.json diff --git a/qw11q/connections.json b/qw11q/connections.json new file mode 100644 index 00000000..8de2d21a --- /dev/null +++ b/qw11q/connections.json @@ -0,0 +1,189 @@ +{ + "kind": "qm", + "channels": { + "A1A4/drive_lo": { + "instrument": "octave4", + "port": "o2" + }, + "A2A3/drive_lo": { + "instrument": "octave4", + "port": "o4" + }, + "A5D5/drive_lo": { + "instrument": "octave6", + "port": "o2" + }, + "A6D4/drive_lo": { + "instrument": "octave6", + "port": "o4" + }, + "B1/drive_lo": { + "instrument": "octave2", + "port": "o2" + }, + "B2/drive_lo": { + "instrument": "octave2", + "port": "o4" + }, + "B3/drive_lo": { + "instrument": "octave3", + "port": "o1" + }, + "B4/drive_lo": { + "instrument": "octave3", + "port": "o4" + }, + "B5/drive_lo": { + "instrument": "octave3", + "port": "o3" + }, + "D1/drive_lo": { + "instrument": "octave5", + "port": "o2" + }, + "D2D3/drive_lo": { + "instrument": "octave5", + "port": "o4" + }, + "A/probe_lo": { + "instrument": "octave4", + "port": "o1" + }, + "B/probe_lo": { + "instrument": "octave2", + "port": "o1" + }, + "D/probe_lo": { + "instrument": "octave5", + "port": "o1" + }, + "A1/flux": { + "instrument": "con7", + "port": "o3" + }, + "A2/flux": { + "instrument": "con7", + "port": "o4" + }, + "A3/flux": { + "instrument": "con7", + "port": "o5" + }, + "A4/flux": { + "instrument": "con7", + "port": "o6" + }, + "A5/flux": { + "instrument": "con7", + "port": "o7" + }, + "A6/flux": { + "instrument": "con7", + "port": "o8" + }, + "B1/flux": { + "instrument": "con4", + "port": "o1" + }, + "B2/flux": { + "instrument": "con4", + "port": "o2" + }, + "B3/flux": { + "instrument": "con4", + "port": "o3" + }, + "B4/flux": { + "instrument": "con4", + "port": "o4" + }, + "B5/flux": { + "instrument": "con4", + "port": "o5" + }, + "D1/flux": { + "instrument": "con9", + "port": "o3" + }, + "D2/flux": { + "instrument": "con9", + "port": "o4" + }, + "D3/flux": { + "instrument": "con9", + "port": "o5" + }, + "D4/flux": { + "instrument": "con9", + "port": "o6" + }, + "D5/flux": { + "instrument": "con9", + "port": "o7" + }, + "A1/acquisition": { + "instrument": "con5", + "port": "i1" + }, + "A2/acquisition": { + "instrument": "con5", + "port": "i1" + }, + "A3/acquisition": { + "instrument": "con5", + "port": "i1" + }, + "A4/acquisition": { + "instrument": "con5", + "port": "i1" + }, + "A5/acquisition": { + "instrument": "con5", + "port": "i1" + }, + "A6/acquisition": { + "instrument": "con5", + "port": "i1" + }, + "B1/acquisition": { + "instrument": "con2", + "port": "i1" + }, + "B2/acquisition": { + "instrument": "con2", + "port": "i1" + }, + "B3/acquisition": { + "instrument": "con2", + "port": "i1" + }, + "B4/acquisition": { + "instrument": "con2", + "port": "i1" + }, + "B5/acquisition": { + "instrument": "con2", + "port": "i1" + }, + "D1/acquisition": { + "instrument": "con6", + "port": "i1" + }, + "D2/acquisition": { + "instrument": "con6", + "port": "i1" + }, + "D3/acquisition": { + "instrument": "con6", + "port": "i1" + }, + "D4/acquisition": { + "instrument": "con6", + "port": "i1" + }, + "D5/acquisition": { + "instrument": "con6", + "port": "i1" + } + } +} diff --git a/qw5q_platinum/connections.json b/qw5q_platinum/connections.json new file mode 100644 index 00000000..c7ada2c8 --- /dev/null +++ b/qw5q_platinum/connections.json @@ -0,0 +1,70 @@ +{ + "kind": "qm", + "channels": { + "01/drive_lo": { + "instrument": "octave1", + "port": "o2", + "output_mode": "always_on" + }, + "2/drive_lo": { + "instrument": "octave1", + "port": "o1", + "output_mode": "always_on" + }, + "3/drive_lo": { + "instrument": "octave1", + "port": "o4", + "output_mode": "always_on" + }, + "4/drive_lo": { + "instrument": "octave2", + "port": "o2", + "output_mode": "always_on" + }, + "probe_lo": { + "instrument": "octave2", + "port": "o1", + "output_mode": "always_on" + }, + "0/flux": { + "instrument": "con1", + "port": "4/o4" + }, + "1/flux": { + "instrument": "con1", + "port": "4/o1" + }, + "2/flux": { + "instrument": "con1", + "port": "4/o3" + }, + "3/flux": { + "instrument": "con1", + "port": "4/o2" + }, + "4/flux": { + "instrument": "con1", + "port": "4/o5" + }, + "0/acquisition": { + "instrument": "con1", + "port": "2/i1" + }, + "1/acquisition": { + "instrument": "con1", + "port": "2/i1" + }, + "2/acquisition": { + "instrument": "con1", + "port": "2/i1" + }, + "3/acquisition": { + "instrument": "con1", + "port": "2/i1" + }, + "4/acquisition": { + "instrument": "con1", + "port": "2/i1" + } + } +} From 746c467cc524af87b8ef37bc411fdfa450290130 Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:31:20 +0400 Subject: [PATCH 8/9] fix: 0 instead of null relative_phase --- convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/convert.py b/convert.py index b3b9563b..9eb79734 100644 --- a/convert.py +++ b/convert.py @@ -156,7 +156,7 @@ def pulse(o: dict) -> dict: "duration": o["duration"], "amplitude": o["amplitude"], "envelope": envelope(o["shape"]), - "relative_phase": o.get("phase"), + "relative_phase": o.get("phase", 0.0), } From ea39694ce60dbb8a4ded6e7840c0aae537cc286e Mon Sep 17 00:00:00 2001 From: Stavros Efthymiou <35475381+stavros11@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:50:01 +0400 Subject: [PATCH 9/9] fix: time of flight for QM platforms --- convert.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/convert.py b/convert.py index 9eb79734..1cb2dc75 100644 --- a/convert.py +++ b/convert.py @@ -13,6 +13,8 @@ NONSERIAL = lambda: None """Raise an error if survives in the final object to be serialized.""" +QM_TIME_OF_FLIGHT = 224 +"""Default time of flight for QM platforms (in 0.1 this was hard-coded in platform.py).""" def channel_from_pulse(pulse: dict) -> dict: @@ -34,7 +36,11 @@ def qm_configs(conf: dict, instruments: dict, instrument_channels: dict) -> dict kind = conf[channel]["kind"] if kind == "acquisition": conf[channel].update( - {"kind": "qm-acquisition", "gain": settings.get("gain", 0)} + { + "kind": "qm-acquisition", + "delay": QM_TIME_OF_FLIGHT, + "gain": settings.get("gain", 0), + } ) elif kind == "dc": conf[channel].update(