From d53fcc5079d9fa10987e919abd9b0343f753b4b0 Mon Sep 17 00:00:00 2001 From: David Yonge-Mallo Date: Thu, 21 Dec 2023 01:51:28 +0100 Subject: [PATCH 1/3] Add support for Spider QASM as option for Input Circuit. See https://github.com/Quantomatic/pyzx/issues/192 for context. --- zxlive/common.py | 6 ++++++ zxlive/edit_panel.py | 13 ++++++++++--- zxlive/settings_dialog.py | 3 ++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/zxlive/common.py b/zxlive/common.py index e2db7a82..de9ed90c 100644 --- a/zxlive/common.py +++ b/zxlive/common.py @@ -35,6 +35,7 @@ class ToolType(IntEnum): "path/custom-rules": "lemmas/", "color-scheme": "modern-red-green", "snap-granularity": '4', + "qasm-flavor": 'openqasm', "tikz/boundary-export": pyzx.settings.tikz_classes['boundary'], "tikz/Z-spider-export": pyzx.settings.tikz_classes['Z'], @@ -82,6 +83,11 @@ class ToolType(IntEnum): 'gidney': "Gidney's Black & White", } +qasm_flavor = { + 'openqasm': "standard OpenQASM", + 'sqasm': "Spider QASM", + 'sqasm-no-simplification': "Spider QASM (no simplification)", +} # Initialise settings settings = QSettings("zxlive", "zxlive") diff --git a/zxlive/edit_panel.py b/zxlive/edit_panel.py index 1bf64b54..7f7dd6f5 100644 --- a/zxlive/edit_panel.py +++ b/zxlive/edit_panel.py @@ -3,10 +3,10 @@ import copy from typing import Iterator -from PySide6.QtCore import Signal +from PySide6.QtCore import Signal, QSettings from PySide6.QtGui import QAction from PySide6.QtWidgets import (QToolButton) -from pyzx import EdgeType, VertexType +from pyzx import EdgeType, VertexType, sqasm from pyzx.circuit.qasmparser import QASMParser from pyzx.symbolic import Poly @@ -73,11 +73,18 @@ def _start_derivation(self) -> None: self.start_derivation_signal.emit(new_g) def _input_circuit(self) -> None: + settings = QSettings("zxlive", "zxlive") + flavor = settings.value("qasm-flavor") qasm = create_circuit_dialog(self) if qasm is not None: new_g = copy.deepcopy(self.graph_scene.g) try: - circ = QASMParser().parse(qasm, strict=False).to_graph() + if flavor == 'sqasm': + circ = sqasm(qasm) + elif flavor == 'sqasm-no-simplification': + circ = sqasm(qasm, simplify=False) + else: + circ = QASMParser().parse(qasm, strict=False).to_graph() except TypeError as err: show_error_msg("Invalid circuit", str(err)) return diff --git a/zxlive/settings_dialog.py b/zxlive/settings_dialog.py index c1a88147..1f4b4779 100644 --- a/zxlive/settings_dialog.py +++ b/zxlive/settings_dialog.py @@ -27,7 +27,7 @@ import pyzx -from .common import set_pyzx_tikz_settings, colors, setting, color_schemes, defaults +from .common import set_pyzx_tikz_settings, colors, setting, color_schemes, qasm_flavor, defaults if TYPE_CHECKING: from .mainwindow import MainWindow @@ -63,6 +63,7 @@ def __init__(self, main_window: MainWindow) -> None: self.add_setting(form_general, "color-scheme", "Color scheme", 'combo',data=color_schemes) self.add_setting(form_general, "snap-granularity", "Snap-to-grid granularity", 'combo', data = {'2': "2", '4': "4", '8': "8", '16': "16"}) + self.add_setting(form_general, "qasm-flavor", "Input Circuit as", 'combo', data=qasm_flavor) self.prev_color_scheme = self.settings.value("color-scheme") vlayout.addStretch() From 35372cb26dff4fc42ca0dfc4d4a562900711e928 Mon Sep 17 00:00:00 2001 From: David Yonge-Mallo Date: Thu, 21 Dec 2023 02:36:33 +0100 Subject: [PATCH 2/3] Defer to default value for color-scheme instead of hard-coded value on init. --- zxlive/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zxlive/common.py b/zxlive/common.py index de9ed90c..6274a926 100644 --- a/zxlive/common.py +++ b/zxlive/common.py @@ -151,7 +151,7 @@ class Colors(object): w_output_pressed: QColor = QColor("#444444") outline: QColor = QColor("#000000") - def __init__(self, color_scheme:str='modern-red-green'): + def __init__(self, color_scheme:str): self.set_color_scheme(color_scheme) def set_color_scheme(self, color_scheme: str) -> None: @@ -193,7 +193,7 @@ def set_color_scheme(self, color_scheme: str) -> None: settings = QSettings("zxlive", "zxlive") color_scheme = settings.value("color-scheme") -if color_scheme is None: color_scheme = 'modern-red-green' +if color_scheme is None: color_scheme = str(defaults["color-scheme"]) else: color_scheme = str(color_scheme) colors = Colors(color_scheme) From 5f830a25a9c9eed3d2e225a97e2f1af3ca5612b8 Mon Sep 17 00:00:00 2001 From: David Yonge-Mallo Date: Fri, 22 Dec 2023 01:23:24 +0100 Subject: [PATCH 3/3] Make circuit input more general to allow other formats in the future. --- zxlive/common.py | 4 ++-- zxlive/dialogs.py | 12 +++--------- zxlive/edit_panel.py | 23 ++++++++++++++++------- zxlive/settings_dialog.py | 4 ++-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/zxlive/common.py b/zxlive/common.py index 6274a926..76e5644f 100644 --- a/zxlive/common.py +++ b/zxlive/common.py @@ -35,7 +35,7 @@ class ToolType(IntEnum): "path/custom-rules": "lemmas/", "color-scheme": "modern-red-green", "snap-granularity": '4', - "qasm-flavor": 'openqasm', + "input-circuit-format": 'openqasm', "tikz/boundary-export": pyzx.settings.tikz_classes['boundary'], "tikz/Z-spider-export": pyzx.settings.tikz_classes['Z'], @@ -83,7 +83,7 @@ class ToolType(IntEnum): 'gidney': "Gidney's Black & White", } -qasm_flavor = { +input_circuit_formats = { 'openqasm': "standard OpenQASM", 'sqasm': "Spider QASM", 'sqasm-no-simplification': "Spider QASM (no simplification)", diff --git a/zxlive/dialogs.py b/zxlive/dialogs.py index bda11d38..52018fa7 100644 --- a/zxlive/dialogs.py +++ b/zxlive/dialogs.py @@ -102,15 +102,9 @@ def import_diagram_dialog(parent: QWidget) -> Optional[ImportGraphOutput | Impor return import_diagram_from_file(file_path, selected_filter) -def create_circuit_dialog(parent: QWidget) -> Optional[str]: - """Shows a dialog to input a circuit in QASM format.""" - explanation = """Write a circuit in QASM format. Example: - qreg q[3]; - cx q[0], q[1]; - h q[2]; - ccx q[0], q[1], q[2]; - """ - s, success = QInputDialog.getMultiLineText(parent, "Circuit input", explanation, "qreg q[3];\n") +def create_circuit_dialog(explanation: str, example: str, parent: QWidget) -> Optional[str]: + """Shows a dialog to input a circuit.""" + s, success = QInputDialog.getMultiLineText(parent, "Circuit input", explanation, example) return s if success else None diff --git a/zxlive/edit_panel.py b/zxlive/edit_panel.py index 7f7dd6f5..f17e29d0 100644 --- a/zxlive/edit_panel.py +++ b/zxlive/edit_panel.py @@ -12,7 +12,7 @@ from .base_panel import ToolbarSection from .commands import UpdateGraph -from .common import GraphT +from .common import GraphT, input_circuit_formats from .dialogs import show_error_msg, create_circuit_dialog from .editor_base_panel import EditorBasePanel from .graphscene import EditGraphScene @@ -74,14 +74,24 @@ def _start_derivation(self) -> None: def _input_circuit(self) -> None: settings = QSettings("zxlive", "zxlive") - flavor = settings.value("qasm-flavor") - qasm = create_circuit_dialog(self) + circuit_format = str(settings.value("input-circuit-format")) + explanations = { + 'openqasm': "Write a circuit in QASM format.", + 'sqasm': "Write a circuit in Spider QASM format.", + 'sqasm-no-simplification': "Write a circuit in Spider QASM format. No simplification will be performed.", + } + examples = { + 'openqasm': "qreg q[3];\ncx q[0], q[1];\nh q[2];\nccx q[0], q[1], q[2];", + 'sqasm': "qreg q[1];\nqreg A[2];\n;s A[1];\n;cx q[0], A[0];\n;cx q[0], A[1];", + 'sqasm-no-simplification': "qreg q[1];\nqreg Z[2];\ncx q[0], Z[0];\ncx q[0], Z[1];\ns Z[1];", + } + qasm = create_circuit_dialog(explanations[circuit_format], examples[circuit_format], self) if qasm is not None: new_g = copy.deepcopy(self.graph_scene.g) try: - if flavor == 'sqasm': + if circuit_format == 'sqasm': circ = sqasm(qasm) - elif flavor == 'sqasm-no-simplification': + elif circuit_format == 'sqasm-no-simplification': circ = sqasm(qasm, simplify=False) else: circ = QASMParser().parse(qasm, strict=False).to_graph() @@ -89,11 +99,10 @@ def _input_circuit(self) -> None: show_error_msg("Invalid circuit", str(err)) return except Exception: - show_error_msg("Invalid circuit", "Couldn't parse QASM code") + show_error_msg("Invalid circuit", f"Couldn't parse code as {input_circuit_formats[circuit_format]}.") return new_verts, new_edges = new_g.merge(circ) cmd = UpdateGraph(self.graph_view, new_g) self.undo_stack.push(cmd) self.graph_scene.select_vertices(new_verts) - diff --git a/zxlive/settings_dialog.py b/zxlive/settings_dialog.py index 1f4b4779..089d772b 100644 --- a/zxlive/settings_dialog.py +++ b/zxlive/settings_dialog.py @@ -27,7 +27,7 @@ import pyzx -from .common import set_pyzx_tikz_settings, colors, setting, color_schemes, qasm_flavor, defaults +from .common import set_pyzx_tikz_settings, colors, setting, color_schemes, input_circuit_formats, defaults if TYPE_CHECKING: from .mainwindow import MainWindow @@ -63,7 +63,7 @@ def __init__(self, main_window: MainWindow) -> None: self.add_setting(form_general, "color-scheme", "Color scheme", 'combo',data=color_schemes) self.add_setting(form_general, "snap-granularity", "Snap-to-grid granularity", 'combo', data = {'2': "2", '4': "4", '8': "8", '16': "16"}) - self.add_setting(form_general, "qasm-flavor", "Input Circuit as", 'combo', data=qasm_flavor) + self.add_setting(form_general, "input-circuit-format", "Input Circuit as", 'combo', data=input_circuit_formats) self.prev_color_scheme = self.settings.value("color-scheme") vlayout.addStretch()