diff --git a/ACID/src/acid/__init__.py b/ACID/src/acid/__init__.py index e9a0469..07c6095 100644 --- a/ACID/src/acid/__init__.py +++ b/ACID/src/acid/__init__.py @@ -1,10 +1,9 @@ __all__ = [ + "BBMidCycle", + "Connection", + "Device", + "Embedding", "GroupRing", "Monomial", "Polynomial", - "Embedding", - "Device", - "Connection", - "BBMidCycle", ] - diff --git a/ACID/src/acid/analysis/__init__.py b/ACID/src/acid/analysis/__init__.py index 96fe9af..a8a0dc4 100644 --- a/ACID/src/acid/analysis/__init__.py +++ b/ACID/src/acid/analysis/__init__.py @@ -1,2 +1 @@ """Analysis helpers for reports and schedule introspection.""" - diff --git a/ACID/src/acid/analysis/gauge_fix_nkd.py b/ACID/src/acid/analysis/gauge_fix_nkd.py index 37852d9..092119d 100644 --- a/ACID/src/acid/analysis/gauge_fix_nkd.py +++ b/ACID/src/acid/analysis/gauge_fix_nkd.py @@ -3,7 +3,6 @@ import time from dataclasses import dataclass from itertools import product -from typing import Dict, List, Tuple, Optional from acid.defects.defective_code import DefectiveCode from acid.pauli import PauliString, StabiliserCode @@ -15,15 +14,17 @@ class GaugeFixNKDResult: combos_total: int eval_count: int timed_out: bool - best_choice: Optional[List[int]] - best_n: Optional[int] - best_k: Optional[int] - best_d: Optional[int] + best_choice: list[int] | None + best_n: int | None + best_k: int | None + best_d: int | None -def _basis_rows_to_Hx_Hz(rows: List[PauliString], n: int) -> Tuple[List[List[int]], List[List[int]]]: - Hx: List[List[int]] = [] - Hz: List[List[int]] = [] +def _basis_rows_to_Hx_Hz( + rows: list[PauliString], n: int +) -> tuple[list[list[int]], list[list[int]]]: + Hx: list[list[int]] = [] + Hz: list[list[int]] = [] for p in rows: if any(b & 1 for b in p.Z): # Treat as Z row @@ -36,7 +37,7 @@ def _basis_rows_to_Hx_Hz(rows: List[PauliString], n: int) -> Tuple[List[List[int def _build_code_for_choice( dcode: DefectiveCode, - choice_bits: List[int], + choice_bits: list[int], ) -> StabiliserCode: """ Build a CSS StabiliserCode by gauge-fixing: @@ -48,7 +49,7 @@ def _build_code_for_choice( # Untouched + products base = dcode.midcycle_untouched_stabilisers() prod = dcode.midcycle_product_stabilisers() - rows: List[PauliString] = [] + rows: list[PauliString] = [] rows.extend(base.rows) if prod is not None: rows.extend(prod.rows) @@ -62,7 +63,7 @@ def _build_code_for_choice( rows.append(Gz[i]) # Convert to Hx/Hz Hx_rows, Hz_rows = _basis_rows_to_Hx_Hz(rows, n) - labels: List[str] = [f"r{i}" for i in range(len(Hx_rows) + len(Hz_rows))] + labels: list[str] = [f"r{i}" for i in range(len(Hx_rows) + len(Hz_rows))] return StabiliserCode(num_qubits=n, row_labels=labels, Hx=Hx_rows, Hz=Hz_rows) @@ -86,10 +87,10 @@ def gauge_fixed_nkd( g = min(len(Gx), len(Gz)) combos_total = 1 << g start = time.monotonic() - best_d: Optional[int] = None - best_n: Optional[int] = None - best_k: Optional[int] = None - best_choice: Optional[List[int]] = None + best_d: int | None = None + best_n: int | None = None + best_k: int | None = None + best_choice: list[int] | None = None eval_count = 0 for bits in product([0, 1], repeat=g): # Check global timeout @@ -134,4 +135,3 @@ def gauge_fixed_nkd( best_k=best_k, best_d=best_d, ) - diff --git a/ACID/src/acid/analysis/report.py b/ACID/src/acid/analysis/report.py index 6107220..c00cc0b 100644 --- a/ACID/src/acid/analysis/report.py +++ b/ACID/src/acid/analysis/report.py @@ -1,26 +1,25 @@ from __future__ import annotations from pathlib import Path -from typing import Dict, List, Set -from acid.defects.defective_code import DefectiveCode from acid.analysis.schedule import analyze_layers +from acid.defects.defective_code import DefectiveCode from acid.defects.syndrome_extraction_circuit import SyndromeExtractionCircuit -def write_schedule_report(out_path: Path, - dcode: DefectiveCode, - Ls: List[int], - *, - solve_time: float = 60.0) -> None: +def write_schedule_report( + out_path: Path, dcode: DefectiveCode, Ls: list[int], *, solve_time: float = 60.0 +) -> None: """ Generic report writer for any DefectiveCode + schedule lengths. Includes stats, per-layer measured/in-process/completed, and product completions. """ - lines: List[str] = [] - lines.append(f"# Schedule Report\n") + lines: list[str] = [] + lines.append("# Schedule Report\n") stats = dcode.stats() - lines.append(f"- Quasis: {stats.get('num_quasi')} nontrivial={stats.get('num_nontrivial')} rank={stats.get('rank')}\n") + lines.append( + f"- Quasis: {stats.get('num_quasi')} nontrivial={stats.get('num_nontrivial')} rank={stats.get('rank')}\n" + ) products = dcode.products_list() prod_members = {p.label: set(p.members) for p in products} interesting = set(dcode.anticommutation_graph().nodes()) @@ -29,26 +28,31 @@ def write_schedule_report(out_path: Path, try: circuit = dcode.schedule(L, solve_time=solve_time) layers = circuit.layers - result = analyze_layers(prod_members, layers, interesting_labels=interesting) + result = analyze_layers( + prod_members, layers, interesting_labels=interesting + ) # Per-layer table - lines.append("\n| Layer | Measured | In-process | Completed |\n|------:|----------|------------|-----------|\n") - for t, rec in enumerate(result['per_layer']): - m = ','.join(rec['measured']) if rec['measured'] else '-' - ip = ','.join(rec['in_process']) if rec['in_process'] else '-' - cp = ','.join(rec['completed']) if rec['completed'] else '-' + lines.append( + "\n| Layer | Measured | In-process | Completed |\n|------:|----------|------------|-----------|\n" + ) + for t, rec in enumerate(result["per_layer"]): + m = ",".join(rec["measured"]) if rec["measured"] else "-" + ip = ",".join(rec["in_process"]) if rec["in_process"] else "-" + cp = ",".join(rec["completed"]) if rec["completed"] else "-" lines.append(f"| {t} | {m} | {ip} | {cp} |\n") # Product completions lines.append("\nCompletions:\n") - for p, compl in sorted(result['product_completions'].items()): + for p, compl in sorted(result["product_completions"].items()): lines.append(f"- {p}: {sorted(compl)}\n") except Exception as e: lines.append(f"- Solve failed: {e}\n") out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text("\n".join(lines)) -def write_schedule_report_from_circuit(out_path: Path, - dcode: DefectiveCode, - circuit: SyndromeExtractionCircuit) -> None: + +def write_schedule_report_from_circuit( + out_path: Path, dcode: DefectiveCode, circuit: SyndromeExtractionCircuit +) -> None: products = dcode.products_list() prod_members = {p.label: set(p.members) for p in products} interesting = set(dcode.anticommutation_graph().nodes()) @@ -56,15 +60,17 @@ def write_schedule_report_from_circuit(out_path: Path, layers = circuit.layers result = analyze_layers(prod_members, layers, interesting_labels=interesting) # Per-layer table - lines.append("\n| Layer | Measured | In-process | Completed |\n|------:|----------|------------|-----------|\n") - for t, rec in enumerate(result['per_layer']): - m = ','.join(rec['measured']) if rec['measured'] else '-' - ip = ','.join(rec['in_process']) if rec['in_process'] else '-' - cp = ','.join(rec['completed']) if rec['completed'] else '-' + lines.append( + "\n| Layer | Measured | In-process | Completed |\n|------:|----------|------------|-----------|\n" + ) + for t, rec in enumerate(result["per_layer"]): + m = ",".join(rec["measured"]) if rec["measured"] else "-" + ip = ",".join(rec["in_process"]) if rec["in_process"] else "-" + cp = ",".join(rec["completed"]) if rec["completed"] else "-" lines.append(f"| {t} | {m} | {ip} | {cp} |\n") # Product completions lines.append("\nCompletions:\n") - for p, compl in sorted(result['product_completions'].items()): + for p, compl in sorted(result["product_completions"].items()): lines.append(f"- {p}: {sorted(compl)}\n") out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text("\n".join(lines)) diff --git a/ACID/src/acid/analysis/schedule.py b/ACID/src/acid/analysis/schedule.py index 7247995..836d5d6 100644 --- a/ACID/src/acid/analysis/schedule.py +++ b/ACID/src/acid/analysis/schedule.py @@ -1,14 +1,14 @@ from __future__ import annotations -from typing import Dict, List, Set - from acid.scheduling.types import SyndromeExtractionLayer -def analyze_layers(product_members: Dict[str, Set[str]], - layers: List[SyndromeExtractionLayer], - *, - interesting_labels: Set[str] | None = None) -> Dict: +def analyze_layers( + product_members: dict[str, set[str]], + layers: list[SyndromeExtractionLayer], + *, + interesting_labels: set[str] | None = None, +) -> dict: """ Generic schedule analysis usable for any code and any schedule: - per-layer measured labels (optionally filtered to 'interesting_labels') @@ -27,17 +27,19 @@ def analyze_layers(product_members: Dict[str, Set[str]], interesting_labels = set() # Progress since last completion per product - progress: Dict[str, Set[str]] = {p: set() for p in product_members} - completions: Dict[str, List[int]] = {p: [] for p in product_members} + progress: dict[str, set[str]] = {p: set() for p in product_members} + completions: dict[str, list[int]] = {p: [] for p in product_members} per_layer = [] for t, layer in enumerate(layers): # actual measured set - all_measured = sorted(stab.label for stab in layer.chosen.keys()) + all_measured = sorted(stab.label for stab in layer.chosen) mset = set(all_measured) # display-only measured (optional filter) if interesting_labels: - measured = sorted([lab for lab in all_measured if lab in interesting_labels]) + measured = sorted( + [lab for lab in all_measured if lab in interesting_labels] + ) else: measured = [] @@ -47,7 +49,7 @@ def analyze_layers(product_members: Dict[str, Set[str]], for p, members in product_members.items(): if mset & members: in_process.append(p) - progress[p] |= (mset & members) + progress[p] |= mset & members # Check completions at end of layer for p, members in product_members.items(): if progress[p] and progress[p] >= members: @@ -55,13 +57,15 @@ def analyze_layers(product_members: Dict[str, Set[str]], completed.append(p) progress[p].clear() - per_layer.append({ - 'measured': measured, - 'in_process': sorted(in_process), - 'completed': sorted(completed), - }) + per_layer.append( + { + "measured": measured, + "in_process": sorted(in_process), + "completed": sorted(completed), + } + ) return { - 'per_layer': per_layer, - 'product_completions': completions, + "per_layer": per_layer, + "product_completions": completions, } diff --git a/ACID/src/acid/base_code.py b/ACID/src/acid/base_code.py index b1da932..9ae8a8c 100644 --- a/ACID/src/acid/base_code.py +++ b/ACID/src/acid/base_code.py @@ -1,42 +1,51 @@ from __future__ import annotations from dataclasses import dataclass -from typing import List, Optional, Tuple + import networkx as nx @dataclass(frozen=True) class StabiliserShape: - pauli_type: str # 'X' or 'Z' - connectivity_subgraph: nx.Graph # nodes 0..k-1 - sec_cycle_length: int # nominal SEC cycle length to use for schedules later - qubit_map: List[int] # len = k; template index -> code qubit id + pauli_type: str # 'X' or 'Z' + connectivity_subgraph: nx.Graph # nodes 0..k-1 + sec_cycle_length: int # nominal SEC cycle length to use for schedules later + qubit_map: list[int] # len = k; template index -> code qubit id label: str # Preference inputs (all optional) - preferred_roots: Optional[List[int]] = None # list of preferred local roots; if None, root not considered for preference - preferred_edges: Optional[dict[tuple[int, int], Optional[List[int]]]] = None # edge -> optional list of required timesteps + preferred_roots: list[int] | None = ( + None # list of preferred local roots; if None, root not considered for preference + ) + preferred_edges: dict[tuple[int, int], list[int] | None] | None = ( + None # edge -> optional list of required timesteps + ) # Solver hints (optional and soft) - schedule_hint: Optional[List[List[tuple[int, int]]]] = None # pre-defined schedule used as a hint only - layer_hint: Optional[int] = None # layer index at which to hint this stabiliser schedule + schedule_hint: list[list[tuple[int, int]]] | None = ( + None # pre-defined schedule used as a hint only + ) + layer_hint: int | None = ( + None # layer index at which to hint this stabiliser schedule + ) # Accepted but unused; maintained for builder compatibility - redundant_edges: Optional[set[tuple[int, int]]] = None + redundant_edges: set[tuple[int, int]] | None = None @dataclass class BaseCode: num_qubits: int connectivity_graph: nx.Graph - shapes: List[StabiliserShape] + shapes: list[StabiliserShape] # Optional: labelled connection classes for visualisation (undirected) - connection_classes: Optional[List[Tuple[int, int, str]]] = None + connection_classes: list[tuple[int, int, str]] | None = None def validate_local_connectivity(self) -> None: G = self.connectivity_graph for sh in self.shapes: S = sh.connectivity_subgraph qmap = sh.qubit_map - for (u, v) in S.edges(): - a = qmap[u]; b = qmap[v] + for u, v in S.edges(): + a = qmap[u] + b = qmap[v] if not G.has_edge(a, b): raise RuntimeError( f"Connectivity mismatch for {sh.label}: edge {(u, v)} -> {(a, b)} not in device" diff --git a/ACID/src/acid/codes/bb/__init__.py b/ACID/src/acid/codes/bb/__init__.py index da167a0..4841be1 100644 --- a/ACID/src/acid/codes/bb/__init__.py +++ b/ACID/src/acid/codes/bb/__init__.py @@ -1,2 +1 @@ """Bivariate bicycle (BB/bb) code builders.""" - diff --git a/ACID/src/acid/codes/bb/algebra.py b/ACID/src/acid/codes/bb/algebra.py index c2888d2..cf08222 100644 --- a/ACID/src/acid/codes/bb/algebra.py +++ b/ACID/src/acid/codes/bb/algebra.py @@ -1,16 +1,19 @@ from __future__ import annotations -from dataclasses import dataclass -from typing import Iterable, Iterator, Tuple, FrozenSet import re +from collections.abc import Iterable, Iterator +from dataclasses import dataclass @dataclass(frozen=True) class GroupRing: + """Represents the group ring Z_l x Z_m, where elements are pairs (a, b) with + a in Z_l and b in Z_m.""" + l: int m: int - def canonical(self, a: int, b: int) -> Tuple[int, int]: + def canonical(self, a: int, b: int) -> tuple[int, int]: al = a % self.l bm = b % self.m return al, bm @@ -27,16 +30,16 @@ def __post_init__(self) -> None: object.__setattr__(self, "a", ca) object.__setattr__(self, "b", cb) - def __mul__(self, other: "Monomial") -> "Monomial": + def __mul__(self, other: Monomial) -> Monomial: if self.ring != other.ring: raise ValueError("Mismatched group rings") return Monomial(self.a + other.a, self.b + other.b, self.ring) - def inv(self) -> "Monomial": + def inv(self) -> Monomial: return Monomial(-self.a, -self.b, self.ring) @classmethod - def from_str(cls, s: str, ring: GroupRing) -> "Monomial": + def from_str(cls, s: str, ring: GroupRing) -> Monomial: t = s.strip() m = re.fullmatch(r"x\^(\d+)y\^(\d+)", t) if not m: @@ -54,18 +57,18 @@ def __str__(self) -> str: def __repr__(self) -> str: return ( f'Monomial.from_str("{self.as_string()}", ' - f'GroupRing({self.ring.l}, {self.ring.m}))' + f"GroupRing({self.ring.l}, {self.ring.m}))" ) - + def as_LR_tuple(self, left_right: str): - if left_right not in ('L', 'R'): + if left_right not in ("L", "R"): raise ValueError("left_right must be 'L' or 'R'") - return (self.a, self.b, 0 if left_right == 'L' else 1) + return (self.a, self.b, 0 if left_right == "L" else 1) @dataclass(frozen=True) class Polynomial: - terms: FrozenSet[Monomial] + terms: frozenset[Monomial] ring: GroupRing def __post_init__(self) -> None: @@ -76,15 +79,17 @@ def __post_init__(self) -> None: raise ValueError("Term ring mismatch") key = (t.a, t.b) seen[key] = 1 ^ seen.get(key, 0) - canonical = frozenset(Monomial(a, b, self.ring) for (a, b), v in seen.items() if v) + canonical = frozenset( + Monomial(a, b, self.ring) for (a, b), v in seen.items() if v + ) object.__setattr__(self, "terms", canonical) @staticmethod - def from_exponents(exps: Iterable[Tuple[int, int]], ring: GroupRing) -> "Polynomial": + def from_exponents(exps: Iterable[tuple[int, int]], ring: GroupRing) -> Polynomial: return Polynomial(frozenset(Monomial(a, b, ring) for a, b in exps), ring) @staticmethod - def from_string(s: str, ring: GroupRing) -> "Polynomial": + def from_string(s: str, ring: GroupRing) -> Polynomial: t = s.strip().replace(" ", "") if t == "" or t == "0": return Polynomial(frozenset(), ring) @@ -103,11 +108,11 @@ def __iter__(self) -> Iterator[Monomial]: def __len__(self) -> int: return len(self.terms) - def add(self, other: "Polynomial") -> "Polynomial": + def add(self, other: Polynomial) -> Polynomial: if self.ring != other.ring: raise ValueError("Mismatched group rings") # Symmetric difference of term sets (mod 2) - s = set((t.a, t.b) for t in self.terms) + s = {(t.a, t.b) for t in self.terms} for t in other.terms: key = (t.a, t.b) if key in s: @@ -116,7 +121,7 @@ def add(self, other: "Polynomial") -> "Polynomial": s.add(key) return Polynomial(frozenset(Monomial(a, b, self.ring) for a, b in s), self.ring) - def mul(self, other: "Polynomial") -> "Polynomial": + def mul(self, other: Polynomial) -> Polynomial: if self.ring != other.ring: raise ValueError("Mismatched group rings") # Distribute and cancel even multiplicities (mod 2) @@ -127,24 +132,37 @@ def mul(self, other: "Polynomial") -> "Polynomial": b = (t1.b + t2.b) % self.ring.m key = (a, b) counts[key] = 1 ^ counts.get(key, 0) - return Polynomial(frozenset(Monomial(a, b, self.ring) for (a, b), v in counts.items() if v), self.ring) + return Polynomial( + frozenset(Monomial(a, b, self.ring) for (a, b), v in counts.items() if v), + self.ring, + ) - def left_multiply(self, mono: Monomial) -> "Polynomial": + def left_multiply(self, mono: Monomial) -> Polynomial: if mono.ring != self.ring: raise ValueError("Mismatched group rings") return Polynomial( - frozenset(Monomial(mono.a + t.a, mono.b + t.b, self.ring) for t in self.terms), + frozenset( + Monomial(mono.a + t.a, mono.b + t.b, self.ring) for t in self.terms + ), self.ring, ) - def inverse(self) -> "Polynomial": - return Polynomial(frozenset(Monomial((-t.a) % self.ring.l, (-t.b) % self.ring.m, self.ring) for t in self.terms), self.ring) + def inverse(self) -> Polynomial: + return Polynomial( + frozenset( + Monomial((-t.a) % self.ring.l, (-t.b) % self.ring.m, self.ring) + for t in self.terms + ), + self.ring, + ) def as_string(self) -> str: if not self.terms: return "0" # Deterministic order: by a then b - parts = [f"x^{t.a}y^{t.b}" for t in sorted(self.terms, key=lambda t: (t.a, t.b))] + parts = [ + f"x^{t.a}y^{t.b}" for t in sorted(self.terms, key=lambda t: (t.a, t.b)) + ] return "+".join(parts) def __str__(self) -> str: @@ -153,5 +171,5 @@ def __str__(self) -> str: def __repr__(self) -> str: return ( f'Polynomial.from_string("{self.as_string()}", ' - f'GroupRing({self.ring.l}, {self.ring.m}))' + f"GroupRing({self.ring.l}, {self.ring.m}))" ) diff --git a/ACID/src/acid/codes/bb/builder_deg5.py b/ACID/src/acid/codes/bb/builder_deg5.py index 6bea8e9..0a1faed 100644 --- a/ACID/src/acid/codes/bb/builder_deg5.py +++ b/ACID/src/acid/codes/bb/builder_deg5.py @@ -1,15 +1,12 @@ from __future__ import annotations -from dataclasses import dataclass -from typing import List, Tuple - import networkx as nx +from acid.base_code import BaseCode, StabiliserShape from acid.codes.bb.algebra import GroupRing, Monomial, Polynomial +from acid.codes.bb.builder_hexconn import CodeSpec from acid.codes.bb.midcycle import BBMidCycle from acid.embedding import SquareGridEmbedding -from acid.base_code import BaseCode, StabiliserShape -from acid.codes.bb.builder_hexconn import CodeSpec def _h_template() -> nx.Graph: @@ -23,7 +20,9 @@ def _h_template() -> nx.Graph: return H -def build_code_from_spec(spec: CodeSpec) -> Tuple[BaseCode, SquareGridEmbedding, List[Tuple[int, int, str]]]: +def build_code_from_spec( + spec: CodeSpec, +) -> tuple[BaseCode, SquareGridEmbedding, list[tuple[int, int, str]]]: """ Build a BaseCode with degree-5 connectivity derived directly from the BB polynomials. @@ -52,7 +51,9 @@ def build_code_from_spec(spec: CodeSpec) -> Tuple[BaseCode, SquareGridEmbedding, fx = 1 if (l % 2 == 0) else 0 fy = 1 if (m % 2 == 0) else 0 if fx == 0 and fy == 0: - raise ValueError(f"No valid homomorphism for code (l={l}, m={m}) — require at least one even") + raise ValueError( + f"No valid homomorphism for code (l={l}, m={m}) — require at least one even" + ) use_fx = spec.fx use_fy = spec.fy if use_fx is None or use_fy is None: @@ -60,61 +61,64 @@ def build_code_from_spec(spec: CodeSpec) -> Tuple[BaseCode, SquareGridEmbedding, use_fx = fx if use_fx is None else use_fx use_fy = fy if use_fy is None else use_fy - bb = BBMidCycle(ring, A, B, homomorphism_f_x=int(use_fx), homomorphism_f_y=int(use_fy)) + bb = BBMidCycle( + ring, A, B, homomorphism_f_x=int(use_fx), homomorphism_f_y=int(use_fy) + ) embedding = SquareGridEmbedding(ring=bb.ring, pitch=1.0) # For sanity: object stabiliser supports for assert checks (as sets of qubit ids) obj_stabs = [ - set(embedding.qubit_id(*q) for q in q_s) - for s, q_s in bb.stabilizers().items() + {embedding.qubit_id(*q) for q in q_s} for s, q_s in bb.stabilizers().items() ] H = _h_template() SEC_length = 3 - shapes: List[StabiliserShape] = [] - connections: List[Tuple[int, int, str]] = [] + shapes: list[StabiliserShape] = [] + connections: list[tuple[int, int, str]] = [] for ax in range(l): for ay in range(m): q = Monomial(ax, ay, bb.ring) - even_odd = 'O' if bb.even_odd_monomial(q) else 'E' + even_odd = "O" if bb.even_odd_monomial(q) else "E" # Base L/R at q - l_q = embedding.qubit_id(*q.as_LR_tuple('L')) - r_q = embedding.qubit_id(*q.as_LR_tuple('R')) + l_q = embedding.qubit_id(*q.as_LR_tuple("L")) + r_q = embedding.qubit_id(*q.as_LR_tuple("R")) # Neighbours for X - l_a2q = embedding.qubit_id(*(a2 * q).as_LR_tuple('L')) - l_a3q = embedding.qubit_id(*(a3 * q).as_LR_tuple('L')) - r_b2q = embedding.qubit_id(*(b2 * q).as_LR_tuple('R')) - r_b3q = embedding.qubit_id(*(b3 * q).as_LR_tuple('R')) + l_a2q = embedding.qubit_id(*(a2 * q).as_LR_tuple("L")) + l_a3q = embedding.qubit_id(*(a3 * q).as_LR_tuple("L")) + r_b2q = embedding.qubit_id(*(b2 * q).as_LR_tuple("R")) + r_b3q = embedding.qubit_id(*(b3 * q).as_LR_tuple("R")) # Neighbours for Z - r_a2invq = embedding.qubit_id(*(a2.inv() * q).as_LR_tuple('R')) - r_a3invq = embedding.qubit_id(*(a3.inv() * q).as_LR_tuple('R')) - l_b2invq = embedding.qubit_id(*(b2.inv() * q).as_LR_tuple('L')) - l_b3invq = embedding.qubit_id(*(b3.inv() * q).as_LR_tuple('L')) + r_a2invq = embedding.qubit_id(*(a2.inv() * q).as_LR_tuple("R")) + r_a3invq = embedding.qubit_id(*(a3.inv() * q).as_LR_tuple("R")) + l_b2invq = embedding.qubit_id(*(b2.inv() * q).as_LR_tuple("L")) + l_b3invq = embedding.qubit_id(*(b3.inv() * q).as_LR_tuple("L")) # X stabiliser map (ordering matches H edges to actual device connections) x_map = [r_b2q, l_q, r_b3q, l_a2q, r_q, l_a3q] assert set(x_map) in obj_stabs label_x = f"X{even_odd}({ax},{ay})" - shapes.append(StabiliserShape('X', H, SEC_length, x_map, label_x)) + shapes.append(StabiliserShape("X", H, SEC_length, x_map, label_x)) # Z stabiliser map z_map = [r_a2invq, l_q, r_a3invq, l_b2invq, r_q, l_b3invq] assert set(z_map) in obj_stabs label_z = f"Z{even_odd}({ax},{ay})" - shapes.append(StabiliserShape('Z', H, SEC_length, z_map, label_z)) + shapes.append(StabiliserShape("Z", H, SEC_length, z_map, label_z)) # Degree-5 global connectivity edges from l_q - connections.extend([ - (l_q, r_q, 'I'), - (l_q, r_a2invq, 'A2'), - (l_q, r_a3invq, 'A3'), - (l_q, r_b2q, 'B2'), - (l_q, r_b3q, 'B3'), - ]) + connections.extend( + [ + (l_q, r_q, "I"), + (l_q, r_a2invq, "A2"), + (l_q, r_a3invq, "A3"), + (l_q, r_b2q, "B2"), + (l_q, r_b3q, "B3"), + ] + ) # Build global device graph G = nx.Graph() @@ -122,6 +126,11 @@ def build_code_from_spec(spec: CodeSpec) -> Tuple[BaseCode, SquareGridEmbedding, for u, v, _ in connections: G.add_edge(u, v) - base = BaseCode(num_qubits=bb.num_qubits, connectivity_graph=G, shapes=shapes, connection_classes=connections) + base = BaseCode( + num_qubits=bb.num_qubits, + connectivity_graph=G, + shapes=shapes, + connection_classes=connections, + ) base.validate_local_connectivity() return base, embedding, connections diff --git a/ACID/src/acid/codes/bb/builder_hexconn.py b/ACID/src/acid/codes/bb/builder_hexconn.py index 9eac1b0..d65c110 100644 --- a/ACID/src/acid/codes/bb/builder_hexconn.py +++ b/ACID/src/acid/codes/bb/builder_hexconn.py @@ -1,47 +1,66 @@ from __future__ import annotations from dataclasses import dataclass -from typing import List, Tuple, Optional import networkx as nx +from acid.base_code import BaseCode, StabiliserShape from acid.codes.bb.algebra import GroupRing, Monomial, Polynomial from acid.codes.bb.midcycle import BBMidCycle from acid.embedding import SquareGridEmbedding -from acid.base_code import BaseCode, StabiliserShape # Internal lookup of known BB codes by key. The polynomials are given in # human-readable form for documentation (A_str/B_str) and normalised monomial # exponents (ax, ay) after dividing A by y^2 and B by x^2, which does not # change the code but fixes a canonical representative for construction. CODE_TABLE: dict[str, dict] = { - 'bb72': { - 'l': 6, 'm': 6, - 'A_str': 'x^3 + y + y^2', - 'B_str': 'y^3 + x + x^2', - 'a2': (0, 5), 'a3': (3, 4), 'b2': (5, 0), 'b3': (4, 3), - 'fx': 1, 'fy': 1, + "bb72": { + "l": 6, + "m": 6, + "A_str": "x^3 + y + y^2", + "B_str": "y^3 + x + x^2", + "a2": (0, 5), + "a3": (3, 4), + "b2": (5, 0), + "b3": (4, 3), + "fx": 1, + "fy": 1, }, - 'bb108': { - 'l': 9, 'm': 6, - 'A_str': 'x^3 + y + y^2', - 'B_str': 'y^3 + x + x^2', - 'a2': (0, 5), 'a3': (3, 4), 'b2': (8, 0), 'b3': (7, 3), - 'fx': 0, 'fy': 1, + "bb108": { + "l": 9, + "m": 6, + "A_str": "x^3 + y + y^2", + "B_str": "y^3 + x + x^2", + "a2": (0, 5), + "a3": (3, 4), + "b2": (8, 0), + "b3": (7, 3), + "fx": 0, + "fy": 1, }, - 'bb144': { - 'l': 12, 'm': 6, - 'A_str': 'x^3 + y + y^2', - 'B_str': 'y^3 + x + x^2', - 'a2': (0, 5), 'a3': (3, 4), 'b2': (11, 0), 'b3': (10, 3), - 'fx': 1, 'fy': 1, + "bb144": { + "l": 12, + "m": 6, + "A_str": "x^3 + y + y^2", + "B_str": "y^3 + x + x^2", + "a2": (0, 5), + "a3": (3, 4), + "b2": (11, 0), + "b3": (10, 3), + "fx": 1, + "fy": 1, }, - 'bb288': { - 'l': 12, 'm': 12, - 'A_str': 'x^3 + y^7 + y^2', - 'B_str': 'y^3 + x + x^2', - 'a2': (0, 5), 'a3': (3, 10), 'b2': (11, 0), 'b3': (10, 3), - 'fx': 1, 'fy': 1, + "bb288": { + "l": 12, + "m": 12, + "A_str": "x^3 + y^7 + y^2", + "B_str": "y^3 + x + x^2", + "a2": (0, 5), + "a3": (3, 10), + "b2": (11, 0), + "b3": (10, 3), + "fx": 1, + "fy": 1, }, } @@ -52,99 +71,159 @@ def known_code_keys() -> list[str]: @dataclass class CodeSpec: + """Specification for a bivariate bicycle (BB) code with hex connectivity. + + Attributes: + key: Identifier string for the code (e.g. 'bb144'). + l: Size of the cyclic group Z_l (x-direction). + m: Size of the cyclic group Z_m (y-direction). + a2: Exponents (ax, ay) of the second monomial in polynomial A. + a3: Exponents (ax, ay) of the third monomial in polynomial A. + b2: Exponents (bx, by) of the second monomial in polynomial B. + b3: Exponents (bx, by) of the third monomial in polynomial B. + fx: Homomorphism flag for x (0 or 1); required when l is odd. + fy: Homomorphism flag for y (0 or 1); required when m is odd. + """ + key: str l: int m: int - a2: Tuple[int, int] - a3: Tuple[int, int] - b2: Tuple[int, int] - b3: Tuple[int, int] - fx: Optional[int] = None - fy: Optional[int] = None + a2: tuple[int, int] + a3: tuple[int, int] + b2: tuple[int, int] + b3: tuple[int, int] + fx: int | None = None + fy: int | None = None -def _poly_from_mons(ring: GroupRing, mons: List[Tuple[int,int]]) -> Polynomial: +def _poly_from_mons(ring: GroupRing, mons: list[tuple[int, int]]) -> Polynomial: S = {Monomial(ax, ay, ring) for (ax, ay) in mons} return Polynomial(frozenset(S), ring) -def build_code_from_spec(spec: CodeSpec, *, fx: Optional[int] = None, fy: Optional[int] = None) -> Tuple[BaseCode, SquareGridEmbedding, List[Tuple[int,int,str]]]: +def build_code_from_spec( + spec: CodeSpec, *, fx: int | None = None, fy: int | None = None +) -> tuple[BaseCode, SquareGridEmbedding, list[tuple[int, int, str]]]: + """Build a bivariate bicycle (BB) code with hex connectivity from a specification. + + Args: + spec: CodeSpec object containing the code parameters. + fx: Optional override for the homomorphism flag for x (0 or 1). + fy: Optional override for the homomorphism flag for y (0 or 1). + + Returns: + A tuple containing: + - BaseCode: The constructed base code with connectivity and stabiliser shapes. + - SquareGridEmbedding: The embedding of the code in a square grid. + - List[Tuple[int,int,str]]: A list of connections (edges) in the code's + connectivity graph, each represented as (left qubit, right qubit, label). + """ l, m = spec.l, spec.m + # ring which defines the group structure for the code ring = GroupRing(l, m) + + # buidling the monomials one = Monomial(0, 0, ring) a2 = Monomial(*spec.a2, ring) a3 = Monomial(*spec.a3, ring) b2 = Monomial(*spec.b2, ring) b3 = Monomial(*spec.b3, ring) + # building the polynomials A = Polynomial(frozenset({one, a2, a3}), ring) B = Polynomial(frozenset({one, b2, b3}), ring) fx = 1 if (l % 2 == 0) else 0 fy = 1 if (m % 2 == 0) else 0 if fx == 0 and fy == 0: - raise ValueError(f"No valid homomorphism for code (l={l}, m={m}) — require at least one even") + raise ValueError( + f"No valid homomorphism for code (l={l}, m={m}) — require at least one even" + ) use_fx = fx if fx is not None else spec.fx use_fy = fy if fy is not None else spec.fy if use_fx is None or use_fy is None: - raise ValueError(f"Must specify homomorphism fx/fy for code {spec.key}; pass to build_code_from_spec or add to spec") - bb = BBMidCycle(ring, A, B, homomorphism_f_x=int(use_fx), homomorphism_f_y=int(use_fy)) + raise ValueError( + f"Must specify homomorphism fx/fy for code {spec.key}; pass to build_code_from_spec or add to spec" + ) + + # build the BB code and its embedding + bb = BBMidCycle( + ring, A, B, homomorphism_f_x=int(use_fx), homomorphism_f_y=int(use_fy) + ) embedding = SquareGridEmbedding(ring=bb.ring, pitch=1.0) + # cyclical graph of length 6 - ie a hexagon shaped graph hex_graph = nx.cycle_graph(6) + SEC_length = 3 - shapes: List[StabiliserShape] = [] - connections: List[Tuple[int, int, str]] = [] + shapes: list[StabiliserShape] = [] + connections: list[tuple[int, int, str]] = [] obj_stabs = [ - set(embedding.qubit_id(*q) for q in q_s) - for s, q_s in bb.stabilizers().items() + {embedding.qubit_id(*q) for q in q_s} for s, q_s in bb.stabilizers().items() ] for ax in range(l): for ay in range(m): q = Monomial(ax, ay, bb.ring) - even_odd = 'O' if bb.even_odd_monomial(q) else 'E' + even_odd = "O" if bb.even_odd_monomial(q) else "E" + + # left/right qubit for this monomial (a, b) in the embedding + l_q = embedding.qubit_id(*q.as_LR_tuple("L")) + r_q = embedding.qubit_id(*q.as_LR_tuple("R")) - l_q = embedding.qubit_id(*q.as_LR_tuple('L')) - r_q = embedding.qubit_id(*q.as_LR_tuple('R')) + # other qubits part of the x stabilizer support for this monomial (a, b) + l_a2q = embedding.qubit_id(*(a2 * q).as_LR_tuple("L")) + l_a3q = embedding.qubit_id(*(a3 * q).as_LR_tuple("L")) + r_b2q = embedding.qubit_id(*(b2 * q).as_LR_tuple("R")) + r_b3q = embedding.qubit_id(*(b3 * q).as_LR_tuple("R")) - l_a2q = embedding.qubit_id(*(a2 * q).as_LR_tuple('L')) - l_a3q = embedding.qubit_id(*(a3 * q).as_LR_tuple('L')) - r_b2q = embedding.qubit_id(*(b2 * q).as_LR_tuple('R')) - r_b3q = embedding.qubit_id(*(b3 * q).as_LR_tuple('R')) + # x stabilizer support qubits (left/right) for this monomial (a, b) x_map = [r_q, l_a2q, r_b2q, l_q, r_b3q, l_a3q] assert set(x_map) in obj_stabs label = f"X{even_odd}({ax},{ay})" - shapes.append(StabiliserShape('X', hex_graph, SEC_length, x_map, label)) - r_a2invq = embedding.qubit_id(*(a2.inv() * q).as_LR_tuple('R')) - r_a3invq = embedding.qubit_id(*(a3.inv() * q).as_LR_tuple('R')) - l_b2invq = embedding.qubit_id(*(b2.inv() * q).as_LR_tuple('L')) - l_b3invq = embedding.qubit_id(*(b3.inv() * q).as_LR_tuple('L')) + # x stabiliser shape for this monomial (a, b) in the embedding + shapes.append(StabiliserShape("X", hex_graph, SEC_length, x_map, label)) + + # other qubits part of the z stabilizer support for this monomial (a, b) + r_a2invq = embedding.qubit_id(*(a2.inv() * q).as_LR_tuple("R")) + r_a3invq = embedding.qubit_id(*(a3.inv() * q).as_LR_tuple("R")) + l_b2invq = embedding.qubit_id(*(b2.inv() * q).as_LR_tuple("L")) + l_b3invq = embedding.qubit_id(*(b3.inv() * q).as_LR_tuple("L")) + + # z stabilizer support qubits (left/right) for this monomial (a, b) z_map = [r_q, l_b2invq, r_a2invq, l_q, r_a3invq, l_b3invq] assert set(z_map) in obj_stabs label = f"Z{even_odd}({ax},{ay})" - shapes.append(StabiliserShape('Z', hex_graph, SEC_length, z_map, label)) - - r_a2invb2q = embedding.qubit_id(*(a2.inv() * b2 * q).as_LR_tuple('R')) - r_a3invb3q = embedding.qubit_id(*(a3.inv() * b3 * q).as_LR_tuple('R')) - - connections.extend([ - (l_q, r_a2invq, 'A2'), - (l_q, r_a3invq, 'A3'), - (l_q, r_b2q, 'B2'), - (l_q, r_b3q, 'B3'), - (l_q, r_a2invb2q, 'A2B2^-1'), - (l_q, r_a3invb3q, 'A3B3^-1'), - ]) + # z stabiliser shape for this monomial (a, b) in the embedding + shapes.append(StabiliserShape("Z", hex_graph, SEC_length, z_map, label)) + + r_a2invb2q = embedding.qubit_id(*(a2.inv() * b2 * q).as_LR_tuple("R")) + r_a3invb3q = embedding.qubit_id(*(a3.inv() * b3 * q).as_LR_tuple("R")) + + connections.extend( + [ + (l_q, r_a2invq, "A2"), + (l_q, r_a3invq, "A3"), + (l_q, r_b2q, "B2"), + (l_q, r_b3q, "B3"), + (l_q, r_a2invb2q, "A2B2^-1"), + (l_q, r_a3invb3q, "A3B3^-1"), + ] + ) G = nx.Graph() G.add_nodes_from(range(bb.num_qubits)) for u, v, _ in connections: G.add_edge(u, v) - base = BaseCode(num_qubits=bb.num_qubits, connectivity_graph=G, shapes=shapes, connection_classes=connections) + base = BaseCode( + num_qubits=bb.num_qubits, + connectivity_graph=G, + shapes=shapes, + connection_classes=connections, + ) base.validate_local_connectivity() return base, embedding, connections @@ -153,15 +232,17 @@ def get_spec(key: str) -> CodeSpec: key_l = key.lower() cfg = CODE_TABLE.get(key_l) if cfg is None: - raise ValueError(f"Unknown code key: {key}. Known keys: {', '.join(known_code_keys())}") + raise ValueError( + f"Unknown code key: {key}. Known keys: {', '.join(known_code_keys())}" + ) return CodeSpec( key=key_l, - l=int(cfg['l']), - m=int(cfg['m']), - a2=tuple(cfg['a2']), - a3=tuple(cfg['a3']), - b2=tuple(cfg['b2']), - b3=tuple(cfg['b3']), - fx=int(cfg['fx']) if 'fx' in cfg else None, - fy=int(cfg['fy']) if 'fy' in cfg else None, + l=int(cfg["l"]), + m=int(cfg["m"]), + a2=tuple(cfg["a2"]), + a3=tuple(cfg["a3"]), + b2=tuple(cfg["b2"]), + b3=tuple(cfg["b3"]), + fx=int(cfg["fx"]) if "fx" in cfg else None, + fy=int(cfg["fy"]) if "fy" in cfg else None, ) diff --git a/ACID/src/acid/codes/bb/midcycle.py b/ACID/src/acid/codes/bb/midcycle.py index 79e477d..1df93f8 100644 --- a/ACID/src/acid/codes/bb/midcycle.py +++ b/ACID/src/acid/codes/bb/midcycle.py @@ -1,13 +1,10 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Dict, Iterable, List, Set, Tuple from acid.codes.bb.algebra import GroupRing, Monomial, Polynomial from acid.pauli import StabiliserCode -import numpy as np - @dataclass class BBMidCycle: @@ -32,59 +29,65 @@ def __post_init__(self): assert False self.num_qubits = self.l * self.m * 2 - def even_odd_coords(self,a: int, b:int, _c: int) -> int: - return (a*self.homomorphism_f_x+b*self.homomorphism_f_y) % 2 - - def even_odd_monomial(self,g: Monomial) -> int: - return self.even_odd_coords(g.a,g.b,0) + def even_odd_coords(self, a: int, b: int) -> int: + """Return the parity of the coordinates (a, b) under the homomorphism f_x, f_y.""" + return (a * self.homomorphism_f_x + b * self.homomorphism_f_y) % 2 + + def even_odd_monomial(self, g: Monomial) -> int: + """Return the parity of the coordinates of a monomial g under the homomorphism f_x, f_y.""" + return self.even_odd_coords(g.a, g.b) - def stabilizers(self) -> Dict[Tuple[int, int, str], Set[Tuple[int, int, int]]]: - out: Dict[Tuple[int, int, str], Set[Tuple[int, int, int]]] = {} + def stabilizers(self) -> dict[tuple[int, int, str], set[tuple[int, int, int]]]: + """Returns a dictionary mapping each stabilizer (a, b, basis) to its support as a set of + qubit coordinates (a, b, c [0 for left, 1 for right]).""" + out: dict[tuple[int, int, str], set[tuple[int, int, int]]] = {} for a in range(self.ring.l): for b in range(self.ring.m): g = Monomial(a, b, self.ring) - X_support: Set[Tuple[int, int, int]] = set() + X_support: set[tuple[int, int, int]] = set() for t in self.A: h = t * g - X_support.add((h.a, h.b,0)) + X_support.add((h.a, h.b, 0)) for t in self.B: h = t * g - X_support.add((h.a, h.b,1)) + X_support.add((h.a, h.b, 1)) out[(g.a, g.b, "X")] = X_support - Z_support: Set[Tuple[int, int, int]] = set() + Z_support: set[tuple[int, int, int]] = set() for t in self.B: h = t.inv() * g - Z_support.add((h.a, h.b,0)) + Z_support.add((h.a, h.b, 0)) for t in self.A: h = t.inv() * g - Z_support.add((h.a, h.b,1)) + Z_support.add((h.a, h.b, 1)) out[(g.a, g.b, "Z")] = Z_support return out def midcycle_parity_check_matrix(self) -> StabiliserCode: + """Return the mid-cycle parity check matrix as a StabiliserCode object.""" n = self.num_qubits + def qid(a: int, b: int, c: int) -> int: a0, b0 = self.ring.canonical(a, b) return ((a0 * self.ring.m) + b0) * 2 + (c & 1) + stabs = self.stabilizers() - x_keys = [(a, b, basis) for (a, b, basis) in stabs.keys() if basis == 'X'] - z_keys = [(a, b, basis) for (a, b, basis) in stabs.keys() if basis == 'Z'] + x_keys = [(a, b, basis) for (a, b, basis) in stabs if basis == "X"] + z_keys = [(a, b, basis) for (a, b, basis) in stabs if basis == "Z"] Hx: list[list[int]] = [] Hz: list[list[int]] = [] labels: list[str] = [] for a, b, _ in sorted(x_keys): row = [0] * n - for (aa, bb, cc) in stabs[(a, b, 'X')]: + for aa, bb, cc in stabs[(a, b, "X")]: row[qid(aa, bb, cc)] ^= 1 if any(row): Hx.append(row) labels.append(f"X({a},{b})") for a, b, _ in sorted(z_keys): row = [0] * n - for (aa, bb, cc) in stabs[(a, b, 'Z')]: + for aa, bb, cc in stabs[(a, b, "Z")]: row[qid(aa, bb, cc)] ^= 1 if any(row): Hz.append(row) labels.append(f"Z({a},{b})") return StabiliserCode(num_qubits=n, row_labels=labels, Hx=Hx, Hz=Hz) - diff --git a/ACID/src/acid/codes/colour/__init__.py b/ACID/src/acid/codes/colour/__init__.py index ab02f6c..d385ee8 100644 --- a/ACID/src/acid/codes/colour/__init__.py +++ b/ACID/src/acid/codes/colour/__init__.py @@ -1,10 +1,9 @@ -from .square import build_colour_square_code, in_bounds_square from .hex import build_colour_hex_code, in_bounds_hex +from .square import build_colour_square_code, in_bounds_square __all__ = [ - "build_colour_square_code", "build_colour_hex_code", - "in_bounds_square", + "build_colour_square_code", "in_bounds_hex", + "in_bounds_square", ] - diff --git a/ACID/src/acid/codes/colour/hex.py b/ACID/src/acid/codes/colour/hex.py index 22b6edf..dad585a 100644 --- a/ACID/src/acid/codes/colour/hex.py +++ b/ACID/src/acid/codes/colour/hex.py @@ -1,6 +1,5 @@ from __future__ import annotations -from typing import Dict, List, Tuple import networkx as nx from acid.base_code import BaseCode, StabiliserShape @@ -18,20 +17,24 @@ def in_bounds_hex(d: int, x: int, y: int) -> bool: def _path_graph(n: int) -> nx.Graph: - G = nx.Graph(); G.add_nodes_from(range(n)) + G = nx.Graph() + G.add_nodes_from(range(n)) for i in range(n - 1): G.add_edge(i, i + 1) return G def _cycle_graph(n: int) -> nx.Graph: - G = nx.Graph(); G.add_nodes_from(range(n)) + G = nx.Graph() + G.add_nodes_from(range(n)) for i in range(n): G.add_edge(i, (i + 1) % n) return G -def build_colour_hex_code(d: int, *, deg4: bool = False) -> Tuple[BaseCode, Dict[Tuple[int, int], int]]: +def build_colour_hex_code( + d: int, *, deg4: bool = False +) -> tuple[BaseCode, dict[tuple[int, int], int]]: """Colour code on a d x (3/2)(d-1) lattice built from explicit stabiliser shapes. Shapes and placement follow the specification: @@ -55,7 +58,8 @@ def build_colour_hex_code(d: int, *, deg4: bool = False) -> Tuple[BaseCode, Dict H = (3 * (d - 1)) // 2 # Coordinate registry built on demand while placing shapes - coords: Dict[Tuple[int, int], int] = {} + coords: dict[tuple[int, int], int] = {} + def in_dom(x: int, y: int) -> bool: return 0 <= x <= d - 1 and 0 <= y <= H @@ -68,24 +72,31 @@ def ensure_qid(x: int, y: int) -> int: # Global connectivity inferred from shapes G = nx.Graph() - shapes: List[StabiliserShape] = [] + shapes: list[StabiliserShape] = [] - def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tuple[int, int]], sec_len: int = 3) -> None: + def add_shape( + label: str, + nodes_xy: list[tuple[int, int]], + edges_pairs: list[tuple[int, int]], + sec_len: int = 3, + ) -> None: # Skip if any node is out of domain if any(not in_dom(x, y) for (x, y) in nodes_xy): return # Local indexing - local_index = {xy: i for i, xy in enumerate(nodes_xy)} + # {xy: i for i, xy in enumerate(nodes_xy)} # Ensure qubits and add edges to global graph qmap = [ensure_qid(x, y) for (x, y) in nodes_xy] - for (ai, bi) in edges_pairs: - qa = qmap[ai]; qb = qmap[bi] + for ai, bi in edges_pairs: + qa = qmap[ai] + qb = qmap[bi] if qa == qb: continue G.add_edge(qa, qb) # Build local connectivity graph - LG = nx.Graph(); LG.add_nodes_from(range(len(nodes_xy))) - for (ai, bi) in edges_pairs: + LG = nx.Graph() + LG.add_nodes_from(range(len(nodes_xy))) + for ai, bi in edges_pairs: LG.add_edge(ai, bi) # Preferences: # - Preferred edges are exactly those not added by the 'deg4' rung (edge between local nodes 1 and 4). @@ -95,9 +106,11 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup pref_roots = None if len(nodes_xy) == 6: # Determine if the deg4 rung (1,4) is present; exclude it from preferred edges if so. - rung_present = any(((a == 1 and b == 4) or (a == 4 and b == 1)) for (a, b) in edges_pairs) - pe: dict[Tuple[int, int], None] = {} - for (ai, bi) in edges_pairs: + rung_present = any( + ((a == 1 and b == 4) or (a == 4 and b == 1)) for (a, b) in edges_pairs + ) + pe: dict[tuple[int, int], None] = {} + for ai, bi in edges_pairs: u, v = (ai, bi) if ai <= bi else (bi, ai) if rung_present and (u, v) == (1, 4): continue @@ -109,20 +122,47 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup y0 = nodes_xy[0][1] pref_roots = [2] if (y0 % 2 == 1) else [5] # Emit both X and Z stabilisers with preferences (if any) - shapes.append(StabiliserShape('X', LG, sec_len, qmap, f"{label}X", preferred_roots=pref_roots, preferred_edges=pref_edges)) - shapes.append(StabiliserShape('Z', LG, sec_len, qmap, f"{label}Z", preferred_roots=pref_roots, preferred_edges=pref_edges)) + shapes.append( + StabiliserShape( + "X", + LG, + sec_len, + qmap, + f"{label}X", + preferred_roots=pref_roots, + preferred_edges=pref_edges, + ) + ) + shapes.append( + StabiliserShape( + "Z", + LG, + sec_len, + qmap, + f"{label}Z", + preferred_roots=pref_roots, + preferred_edges=pref_edges, + ) + ) # 1) Basic hex rectangles # Base placements constrained by y <= min(3x-2, -3x + (3d-7)) with x in [0..d-1] - for x in range(0, d): + for x in range(d): y_max = min(3 * x - 2, -3 * x + (3 * d - 7)) if y_max < 0: continue - for y in range(0, y_max + 1): + for y in range(y_max + 1): # Families: (2i,2j) i.e. x even, y even; and (2i-1,2j+1) i.e. x odd, y odd if (x % 2 == 0 and y % 2 == 0) or (x % 2 == 1 and y % 2 == 1): # Node order around the rectangle perimeter - pts = [(x, y), (x, y + 1), (x, y + 2), (x + 1, y + 2), (x + 1, y + 1), (x + 1, y)] + pts = [ + (x, y), + (x, y + 1), + (x, y + 2), + (x + 1, y + 2), + (x + 1, y + 1), + (x + 1, y), + ] # 6-cycle edges cyc_edges = [(i, (i + 1) % 6) for i in range(6)] # Optional deg4 rung: (x,y+1)-(x+1,y+1) corresponds to indices 1 and 4 @@ -133,11 +173,18 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup # Extra rectangle stabs r_extra_max = (d - 3) // 4 - parity_adjust = (d % 4 == 1) - for i in range(0, max(r_extra_max, -1) + 1): + parity_adjust = d % 4 == 1 + for i in range(max(r_extra_max, -1) + 1): # Left extras: (2i+1, 6i+3) x, y = 2 * i + 1, 6 * i + 3 - pts = [(x, y), (x, y + 1), (x, y + 2), (x + 1, y + 2), (x + 1, y + 1), (x + 1, y)] + pts = [ + (x, y), + (x, y + 1), + (x, y + 2), + (x + 1, y + 2), + (x + 1, y + 1), + (x + 1, y), + ] edges = [(i2, (i2 + 1) % 6) for i2 in range(6)] if deg4: edges.append((1, 4)) @@ -146,24 +193,42 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup if not parity_adjust: # Default placement: (d - 2i - 2, 6i + 1) x2, y2 = d - 2 * i - 2, 6 * i + 1 - pts2 = [(x2, y2), (x2, y2 + 1), (x2, y2 + 2), (x2 + 1, y2 + 2), (x2 + 1, y2 + 1), (x2 + 1, y2)] + pts2 = [ + (x2, y2), + (x2, y2 + 1), + (x2, y2 + 2), + (x2 + 1, y2 + 2), + (x2 + 1, y2 + 1), + (x2 + 1, y2), + ] edges2 = [(i2, (i2 + 1) % 6) for i2 in range(6)] if deg4: edges2.append((1, 4)) - add_shape(label=f"hex_extraB({x2},{y2})/", nodes_xy=pts2, edges_pairs=edges2) + add_shape( + label=f"hex_extraB({x2},{y2})/", nodes_xy=pts2, edges_pairs=edges2 + ) else: # Adjusted placement for d % 4 == 1: (d - 2i - 3, 6i + 4) for i = 0 .. d//4 - 1 if i <= (d // 4 - 1): x2, y2 = d - 2 * i - 3, 6 * i + 4 - pts2 = [(x2, y2), (x2, y2 + 1), (x2, y2 + 2), (x2 + 1, y2 + 2), (x2 + 1, y2 + 1), (x2 + 1, y2)] + pts2 = [ + (x2, y2), + (x2, y2 + 1), + (x2, y2 + 2), + (x2 + 1, y2 + 2), + (x2 + 1, y2 + 1), + (x2 + 1, y2), + ] edges2 = [(i2, (i2 + 1) % 6) for i2 in range(6)] if deg4: edges2.append((1, 4)) - add_shape(label=f"hex_extraB({x2},{y2})/", nodes_xy=pts2, edges_pairs=edges2) + add_shape( + label=f"hex_extraB({x2},{y2})/", nodes_xy=pts2, edges_pairs=edges2 + ) # 2) Left triangles: 4-node path (x,y)->(x+1,y)->(x+1,y+1)->(x+1,y+2) lt_max = (d + 1) // 4 - for i in range(0, lt_max + 1): + for i in range(lt_max + 1): x, y = 2 * i, 6 * i nodes = [(x, y), (x + 1, y), (x + 1, y + 1), (x + 1, y + 2)] edges = [(0, 1), (1, 2), (2, 3)] @@ -174,13 +239,13 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup # d % 4 == 3 (e.g., 7,11): (d-2i-3, 6i+4) rt_max = (2 * d - 3) // 4 if parity_adjust: - for i in range(0, rt_max + 1): + for i in range(rt_max + 1): x, y = d - 2 * i - 2, 6 * i + 1 nodes = [(x + 1, y), (x, y), (x, y + 1), (x, y + 2)] edges = [(0, 1), (1, 2), (2, 3)] add_shape(label=f"triR({x},{y})/", nodes_xy=nodes, edges_pairs=edges) else: - for i in range(0, rt_max + 1): + for i in range(rt_max + 1): x, y = d - 2 * i - 3, 6 * i + 4 nodes = [(x + 1, y), (x, y), (x, y + 1), (x, y + 2)] edges = [(0, 1), (1, 2), (2, 3)] @@ -188,19 +253,19 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup # 4) Spurs: 2-node vertical path at the listed positions sp1_max = (d - 3) // 4 - for i in range(0, sp1_max + 1): + for i in range(sp1_max + 1): x, y = 2 * i + 1, 6 * i + 4 nodes = [(x, y), (x, y + 1)] add_shape(label=f"spurA({x},{y})/", nodes_xy=nodes, edges_pairs=[(0, 1)]) sp2_max = (d + 1) // 4 if not parity_adjust: - for i in range(0, sp2_max + 1): + for i in range(sp2_max + 1): x, y = d - 2 * i - 1, 6 * i + 2 nodes = [(x, y), (x, y + 1)] add_shape(label=f"spurB({x},{y})/", nodes_xy=nodes, edges_pairs=[(0, 1)]) else: # Adjusted right spurs: sit on adjusted right extras at (d-2i-2, 6i+5) - for i in range(0, max(d // 4 - 1, -1) + 1): + for i in range(max(d // 4 - 1, -1) + 1): x, y = d - 2 * i - 2, 6 * i + 5 nodes = [(x, y), (x, y + 1)] add_shape(label=f"spurB({x},{y})/", nodes_xy=nodes, edges_pairs=[(0, 1)]) @@ -208,7 +273,7 @@ def add_shape(label: str, nodes_xy: List[Tuple[int, int]], edges_pairs: List[Tup # 5) Squares: 4-cycle at (2i+1, 0) # 5) Squares: 4-cycle at (2i+1, 0), i = 0 .. (d-1)//2 (no parity adjustment) sq_max = (d - 1) // 2 - for i in range(0, sq_max + 1): + for i in range(sq_max + 1): x, y = 2 * i + 1, 0 nodes = [(x, y), (x, y + 1), (x + 1, y + 1), (x + 1, y)] edges = [(0, 1), (1, 2), (2, 3), (3, 0)] diff --git a/ACID/src/acid/codes/colour/square.py b/ACID/src/acid/codes/colour/square.py index a6833b5..a64685f 100644 --- a/ACID/src/acid/codes/colour/square.py +++ b/ACID/src/acid/codes/colour/square.py @@ -1,7 +1,5 @@ from __future__ import annotations -from typing import Dict, List, Tuple, Iterable, Optional -import math import networkx as nx from acid.base_code import BaseCode, StabiliserShape @@ -33,7 +31,9 @@ def in_bounds_square(d: int, x: int, y: int) -> bool: return (lhs1 <= rhs1) and (lhs1 <= rhs2) and (y >= 0) -def _add_cartesian_connectivity(G: nx.Graph, coords: Dict[Tuple[int, int], int], d: int) -> None: +def _add_cartesian_connectivity( + G: nx.Graph, coords: dict[tuple[int, int], int], d: int +) -> None: # Four-neighbour connectivity (N,S,E,W) within bounds for (x, y), q in coords.items(): for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]: @@ -44,47 +44,54 @@ def _add_cartesian_connectivity(G: nx.Graph, coords: Dict[Tuple[int, int], int], def _path_graph(n: int) -> nx.Graph: - G = nx.Graph(); G.add_nodes_from(range(n)) + G = nx.Graph() + G.add_nodes_from(range(n)) for i in range(n - 1): G.add_edge(i, i + 1) return G -def _local_graph_from_coords(order_edges: List[Tuple[Tuple[int, int], Tuple[int, int]]], qmap_list: List[Tuple[int, int]]) -> Tuple[nx.Graph, List[int]]: +def _local_graph_from_coords( + order_edges: list[tuple[tuple[int, int], tuple[int, int]]], + qmap_list: list[tuple[int, int]], +) -> tuple[nx.Graph, list[int]]: """Build a local graph and qubit map from coordinate pairs and desired edges. - qmap_list: list of global coordinate points included in the stabiliser. - order_edges: list of coordinate-pair edges to include if both endpoints are present. Returns (local_graph, qmap) where qmap maps local node index to device qubit id. """ - idx_of: Dict[Tuple[int, int], int] = {xy: i for i, xy in enumerate(qmap_list)} - G = nx.Graph(); G.add_nodes_from(range(len(qmap_list))) + idx_of: dict[tuple[int, int], int] = {xy: i for i, xy in enumerate(qmap_list)} + G = nx.Graph() + G.add_nodes_from(range(len(qmap_list))) for a, b in order_edges: - ia = idx_of.get(a); ib = idx_of.get(b) + ia = idx_of.get(a) + ib = idx_of.get(b) if ia is not None and ib is not None: G.add_edge(int(ia), int(ib)) return G, list(range(len(qmap_list))) -def build_colour_square_code(d: int) -> Tuple[BaseCode, Dict[Tuple[int, int], int]]: +def build_colour_square_code(d: int) -> tuple[BaseCode, dict[tuple[int, int], int]]: _assert_odd_distance(d) offset_x = 1 offset_y = 1 # Qubit placement: all integer (x,y) within domain and bounds - coords: Dict[Tuple[int, int], int] = {} + coords: dict[tuple[int, int], int] = {} qid = 0 for x in range(-1, 2 * d - 2): # inclusive upper bound 2d-3 - for y in range(0, (3 * d - 3) // 2 + 1): + for y in range((3 * d - 3) // 2 + 1): if in_bounds_square(d, x, y): coords[(x + offset_x, y + offset_y)] = qid qid += 1 - G = nx.Graph(); G.add_nodes_from(range(qid)) + G = nx.Graph() + G.add_nodes_from(range(qid)) _add_cartesian_connectivity(G, coords, d) - shapes: List[StabiliserShape] = [] + shapes: list[StabiliserShape] = [] # Helper closures def hasq(x: int, y: int) -> bool: @@ -96,9 +103,9 @@ def idq(x: int, y: int) -> int: half = (d - 1) // 2 def add_inner_outer(color: str, L_of: callable, R_of: callable) -> None: - SEC_length=4 - for i in range(0, half + 1): - for j in range(0, half + 1): + SEC_length = 4 + for i in range(half + 1): + for j in range(half + 1): Lx, Ly = L_of(i, j) Rx, Ry = R_of(i, j) if not (hasq(Lx, Ly) and hasq(Rx, Ry)): @@ -111,43 +118,76 @@ def add_inner_outer(color: str, L_of: callable, R_of: callable) -> None: # schedule_hint = [[], [] , [] , [(1,0)]] # (1,0) means CNOT controlled on 0 targeting 1 # layer_hint 1 for X, layer_hint 0 for Z # Inner stabs: preferred roots as before, plus a preferred edge (L-R) at timestep 3 - pref_edges_inner: Dict[Tuple[int,int], Optional[List[int]]] = { (0,1): [3] } - shapes.append(StabiliserShape('X', path2, SEC_length, qmap2, f"{color}inX({i},{j})", - preferred_roots=[0], preferred_edges=pref_edges_inner)) - shapes.append(StabiliserShape('Z', path2, SEC_length, qmap2, f"{color}inZ({i},{j})", - preferred_roots=[1], preferred_edges=pref_edges_inner)) + pref_edges_inner: dict[tuple[int, int], list[int] | None] = { + (0, 1): [3] + } + shapes.append( + StabiliserShape( + "X", + path2, + SEC_length, + qmap2, + f"{color}inX({i},{j})", + preferred_roots=[0], + preferred_edges=pref_edges_inner, + ) + ) + shapes.append( + StabiliserShape( + "Z", + path2, + SEC_length, + qmap2, + f"{color}inZ({i},{j})", + preferred_roots=[1], + preferred_edges=pref_edges_inner, + ) + ) # Outer: include neighbors up/down/left/right around L and R if present - nb_coords: List[Tuple[int, int]] = [] + nb_coords: list[tuple[int, int]] = [] # Base points first to stabilise indexing order base_points = [(Lx, Ly), (Rx, Ry)] add_points = [ - (Lx, Ly + 1), (Rx, Ry + 1), # above - (Lx, Ly - 1), (Rx, Ry - 1), # below - (Lx - 1, Ly), (Rx + 1, Ry), # left of L, right of R + (Lx, Ly + 1), + (Rx, Ry + 1), # above + (Lx, Ly - 1), + (Rx, Ry - 1), # below + (Lx - 1, Ly), + (Rx + 1, Ry), # left of L, right of R ] for xy in base_points + [p for p in add_points if hasq(*p)]: nb_coords.append(xy) if len(nb_coords) % 2 != 0: - raise AssertionError(f"Outer stabiliser does not have even weight at i={i},j={j}, color={color}") + raise AssertionError( + f"Outer stabiliser does not have even weight at i={i},j={j}, color={color}" + ) # Local connectivity per spec (include only edges whose endpoints exist) - L = (Lx, Ly); R = (Rx, Ry) - UL = (Lx, Ly + 1); UR = (Rx, Ry + 1) - DL = (Lx, Ly - 1) ; DR = (Rx, Ry - 1) - LL = (Lx - 1, Ly); RR = (Rx + 1, Ry) + L = (Lx, Ly) + R = (Rx, Ry) + UL = (Lx, Ly + 1) + UR = (Rx, Ry + 1) + DL = (Lx, Ly - 1) + DR = (Rx, Ry - 1) + LL = (Lx - 1, Ly) + RR = (Rx + 1, Ry) edges = [ (L, R), - (L, UL), (UL, UR), (R, UR), - (L, DL), (DL, DR), (R, DR), - (L, LL), (R, RR), + (L, UL), + (UL, UR), + (R, UR), + (L, DL), + (DL, DR), + (R, DR), + (L, LL), + (R, RR), ] local_graph, local_order = _local_graph_from_coords(edges, nb_coords) coord_to_local = {xy: k for k, xy in enumerate(nb_coords)} qmap = [idq(*nb_coords[k]) for k in local_order] - # Schedule hint (example) for outer (kept commented): # schedule_hint_x = [[], [],[],[(1,0)]] # schedule_hint_z = [[], [],[],[(1,0)]] @@ -172,12 +212,17 @@ def add_inner_outer(color: str, L_of: callable, R_of: callable) -> None: # Preferred edges with timing constraints (if endpoints exist): # DL-L: t=0; DR-R: t=0; LL-L: t=1; RR-R: t=1; UL-L: t=2; UR-R: t=2; L-R: t=3 - preferred_edges: Dict[Tuple[int,int], Optional[List[int]]] = {} - def add_pref(a_xy: Tuple[int,int], b_xy: Tuple[int,int], t: int) -> None: + preferred_edges: dict[tuple[int, int], list[int] | None] = {} + + def add_pref( + a_xy: tuple[int, int], b_xy: tuple[int, int], t: int + ) -> None: if hasq(*a_xy) and hasq(*b_xy): - a = coord_to_local[a_xy]; b = coord_to_local[b_xy] + a = coord_to_local[a_xy] + b = coord_to_local[b_xy] u, v = (a, b) if a <= b else (b, a) preferred_edges[(u, v)] = [int(t)] + add_pref(DL, L, 0) add_pref(DR, R, 0) add_pref(LL, L, 1) @@ -185,34 +230,52 @@ def add_pref(a_xy: Tuple[int,int], b_xy: Tuple[int,int], t: int) -> None: add_pref(UL, L, 2) add_pref(UR, R, 2) # L-R always exists in the local graph - a = coord_to_local[L]; b = coord_to_local[R] + a = coord_to_local[L] + b = coord_to_local[R] u, v = (a, b) if a <= b else (b, a) preferred_edges[(u, v)] = [3] - + # shapes.append(StabiliserShape('X', local_graph, SEC_length, qmap, f"{color}outX({i},{j})", preferred_roots=[0,1])) # shapes.append(StabiliserShape('Z', local_graph, SEC_length, qmap, f"{color}outZ({i},{j})", preferred_roots=[0,1])) - - shapes.append(StabiliserShape('X', local_graph, SEC_length, qmap, f"{color}outX({i},{j})", - preferred_roots=[0], preferred_edges=preferred_edges)) - shapes.append(StabiliserShape('Z', local_graph, SEC_length, qmap, f"{color}outZ({i},{j})", - preferred_roots=[1], preferred_edges=preferred_edges)) + shapes.append( + StabiliserShape( + "X", + local_graph, + SEC_length, + qmap, + f"{color}outX({i},{j})", + preferred_roots=[0], + preferred_edges=preferred_edges, + ) + ) + shapes.append( + StabiliserShape( + "Z", + local_graph, + SEC_length, + qmap, + f"{color}outZ({i},{j})", + preferred_roots=[1], + preferred_edges=preferred_edges, + ) + ) # Red stabs add_inner_outer( - 'R', + "R", L_of=lambda i, j: (4 * i + 2 * j, 3 * j), R_of=lambda i, j: (4 * i + 2 * j + 1, 3 * j), ) # Blue stabs add_inner_outer( - 'B', + "B", L_of=lambda i, j: (4 * i + 2 * j + 2, 3 * j + 1), R_of=lambda i, j: (4 * i + 2 * j + 3, 3 * j + 1), ) # Green stabs add_inner_outer( - 'G', + "G", L_of=lambda i, j: (4 * i + 2 * j, 3 * j + 2), R_of=lambda i, j: (4 * i + 2 * j + 1, 3 * j + 2), ) diff --git a/ACID/src/acid/codes/surface/__init__.py b/ACID/src/acid/codes/surface/__init__.py index fc3aed6..14c5f42 100644 --- a/ACID/src/acid/codes/surface/__init__.py +++ b/ACID/src/acid/codes/surface/__init__.py @@ -1,2 +1 @@ """Surface-code examples (reference/legacy).""" - diff --git a/ACID/src/acid/codes/surface/unrotated_grid.py b/ACID/src/acid/codes/surface/unrotated_grid.py index 96ec72a..1634a14 100644 --- a/ACID/src/acid/codes/surface/unrotated_grid.py +++ b/ACID/src/acid/codes/surface/unrotated_grid.py @@ -1,16 +1,20 @@ from __future__ import annotations -from typing import Dict, List, Tuple import networkx as nx from acid.base_code import BaseCode, StabiliserShape def _path_template(n: int = 4) -> nx.Graph: - G = nx.Graph(); G.add_nodes_from(range(n)); [G.add_edge(i,i+1) for i in range(n-1)]; return G + G = nx.Graph() + G.add_nodes_from(range(n)) + [G.add_edge(i, i + 1) for i in range(n - 1)] + return G -def build_unrotated_surface_grid_code(d: int) -> Tuple[BaseCode, Dict[Tuple[int,int], int]]: +def build_unrotated_surface_grid_code( + d: int, +) -> tuple[BaseCode, dict[tuple[int, int], int]]: """ Distance-d unrotated surface (grid connectivity): - Grid size: (2d-1) x (2d-1), coords in [0..2d-2] @@ -19,31 +23,39 @@ def build_unrotated_surface_grid_code(d: int) -> Tuple[BaseCode, Dict[Tuple[int, - Connectivity: diagonal links between qubits (±1,±1) Returns (G, stabs, coord_to_qid) without constructing a Code object. """ - W = 2 * d - 1; H = 2 * d - 1 - coord_to_qid: Dict[Tuple[int,int], int] = {} - qlist: List[Tuple[int,int]] = [] + W = 2 * d - 1 + H = 2 * d - 1 + coord_to_qid: dict[tuple[int, int], int] = {} + qlist: list[tuple[int, int]] = [] qid = 0 for x in range(W): for y in range(H): if (x % 2 == 0 and y % 2 == 0) or (x % 2 == 1 and y % 2 == 1): - coord_to_qid[(x,y)] = qid; qlist.append((x,y)); qid += 1 + coord_to_qid[(x, y)] = qid + qlist.append((x, y)) + qid += 1 - def hasq(x:int,y:int)->bool: return (x,y) in coord_to_qid - def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] + def hasq(x: int, y: int) -> bool: + return (x, y) in coord_to_qid + + def idq(x: int, y: int) -> int: + return coord_to_qid[(x, y)] # connectivity: diagonals (undirected) - G = nx.Graph(); G.add_nodes_from(range(len(qlist))) - for (x,y), q in coord_to_qid.items(): - for dx,dy in [(-1,-1),(-1,1),(1,-1),(1,1)]: - xn,yn = x+dx, y+dy - if hasq(xn,yn): G.add_edge(q, idq(xn,yn)) + G = nx.Graph() + G.add_nodes_from(range(len(qlist))) + for (x, y), q in coord_to_qid.items(): + for dx, dy in [(-1, -1), (-1, 1), (1, -1), (1, 1)]: + xn, yn = x + dx, y + dy + if hasq(xn, yn): + G.add_edge(q, idq(xn, yn)) # Add boundary reinforcement edges along the four borders to ensure # local stabiliser connectivity is present at boundaries. # Bottom and top rows (horizontal): (2j, y) - (2j+2, y) y_bottom = 0 y_top = H - 1 - for j in range(0, (W - 1) // 2): + for j in range((W - 1) // 2): x1 = 2 * j x2 = x1 + 2 if hasq(x1, y_bottom) and hasq(x2, y_bottom): @@ -53,7 +65,7 @@ def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] # Left and right columns (vertical): (x, 2j) - (x, 2j+2) x_left = 0 x_right = W - 1 - for j in range(0, (H - 1) // 2): + for j in range((H - 1) // 2): y1 = 2 * j y2 = y1 + 2 if hasq(x_left, y1) and hasq(x_left, y2): @@ -61,7 +73,7 @@ def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] if hasq(x_right, y1) and hasq(x_right, y2): G.add_edge(idq(x_right, y1), idq(x_right, y2)) - shapes: List[StabiliserShape] = [] + shapes: list[StabiliserShape] = [] # Build stabilisers using cyclic local connectivity. # - X at (even,odd) @@ -74,13 +86,13 @@ def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] d = hasq(x, y - 1) l = hasq(x - 1, y) # Neighbor list in an order that ensures consecutive pairs are connected - if (u and r and d and not l): + if u and r and d and not l: order = [(x, y + 1), (x + 1, y), (x, y - 1)] - elif (u and r and not d and l): + elif u and r and not d and l: order = [(x - 1, y), (x, y + 1), (x + 1, y)] - elif (u and not r and d and l): + elif u and not r and d and l: order = [(x, y + 1), (x, y - 1), (x - 1, y)] - elif (not u and r and d and l): + elif not u and r and d and l: order = [(x + 1, y), (x, y - 1), (x - 1, y)] else: # Bulk or generic: up, right, down, left filtered @@ -93,7 +105,7 @@ def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] local = nx.cycle_graph(4) else: local = nx.path_graph(3) - shapes.append(StabiliserShape('X', local, 2, neigh_ids, f"X({x},{y})")) + shapes.append(StabiliserShape("X", local, 2, neigh_ids, f"X({x},{y})")) # - Z at (odd,even) for x in range(1, W, 2): @@ -102,13 +114,13 @@ def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] r = hasq(x + 1, y) d = hasq(x, y - 1) l = hasq(x - 1, y) - if (u and r and d and not l): + if u and r and d and not l: order = [(x, y + 1), (x + 1, y), (x, y - 1)] - elif (u and r and not d and l): + elif u and r and not d and l: order = [(x - 1, y), (x, y + 1), (x + 1, y)] - elif (u and not r and d and l): + elif u and not r and d and l: order = [(x, y + 1), (x, y - 1), (x - 1, y)] - elif (not u and r and d and l): + elif not u and r and d and l: order = [(x + 1, y), (x, y - 1), (x - 1, y)] else: order = [(x, y + 1), (x + 1, y), (x, y - 1), (x - 1, y)] @@ -119,7 +131,7 @@ def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] local = nx.cycle_graph(4) else: local = nx.path_graph(3) - shapes.append(StabiliserShape('Z', local, 2, neigh_ids, f"Z({x},{y})")) + shapes.append(StabiliserShape("Z", local, 2, neigh_ids, f"Z({x},{y})")) base = BaseCode(num_qubits=len(qlist), connectivity_graph=G, shapes=shapes) base.validate_local_connectivity() diff --git a/ACID/src/acid/codes/surface/unrotated_grid_square_edges.py b/ACID/src/acid/codes/surface/unrotated_grid_square_edges.py index 0e3c543..718eeb5 100644 --- a/ACID/src/acid/codes/surface/unrotated_grid_square_edges.py +++ b/ACID/src/acid/codes/surface/unrotated_grid_square_edges.py @@ -1,6 +1,5 @@ from __future__ import annotations -from typing import Dict, List, Tuple import networkx as nx from acid.base_code import BaseCode, StabiliserShape @@ -9,11 +8,16 @@ def _cycle4() -> nx.Graph: G = nx.Graph() G.add_nodes_from(range(4)) - G.add_edge(0, 1); G.add_edge(1, 2); G.add_edge(2, 3); G.add_edge(3, 0) + G.add_edge(0, 1) + G.add_edge(1, 2) + G.add_edge(2, 3) + G.add_edge(3, 0) return G -def build_unrotated_surface_grid_square_edges_code(d: int) -> Tuple[BaseCode, Dict[Tuple[int,int], int]]: +def build_unrotated_surface_grid_square_edges_code( + d: int, +) -> tuple[BaseCode, dict[tuple[int, int], int]]: """ Distance-d unrotated surface (grid connectivity with square edges to the boundary). @@ -32,7 +36,7 @@ def build_unrotated_surface_grid_square_edges_code(d: int) -> Tuple[BaseCode, Di """ W = 2 * d + 1 H = 2 * d + 1 - coord_to_qid: Dict[Tuple[int, int], int] = {} + coord_to_qid: dict[tuple[int, int], int] = {} qid = 0 # Place qubits at (even,even) and (odd,odd) within [0..2d], excluding corners for x in range(W): @@ -52,7 +56,7 @@ def idq(x: int, y: int) -> int: G = nx.Graph() G.add_nodes_from(range(qid)) - shapes: List[StabiliserShape] = [] + shapes: list[StabiliserShape] = [] cyc4 = _cycle4() @@ -67,7 +71,7 @@ def idq(x: int, y: int) -> int: if not (hasq(*u) and hasq(*l) and hasq(*dwn) and hasq(*r)): continue qmap = [idq(*u), idq(*l), idq(*dwn), idq(*r)] - shapes.append(StabiliserShape('X', cyc4, 2, qmap, f"X({x},{y})")) + shapes.append(StabiliserShape("X", cyc4, 2, qmap, f"X({x},{y})")) # device edges around the square G.add_edge(qmap[0], qmap[1]) G.add_edge(qmap[1], qmap[2]) @@ -84,23 +88,24 @@ def idq(x: int, y: int) -> int: if not (hasq(*u) and hasq(*l) and hasq(*dwn) and hasq(*r)): continue qmap = [idq(*u), idq(*l), idq(*dwn), idq(*r)] - shapes.append(StabiliserShape('Z', cyc4, 2, qmap, f"Z({x},{y})")) + shapes.append(StabiliserShape("Z", cyc4, 2, qmap, f"Z({x},{y})")) G.add_edge(qmap[0], qmap[1]) G.add_edge(qmap[1], qmap[2]) G.add_edge(qmap[2], qmap[3]) G.add_edge(qmap[3], qmap[0]) # Boundary single-qubit stabilisers (no additional edges) - G1 = nx.Graph(); G1.add_nodes_from([0]) + G1 = nx.Graph() + G1.add_nodes_from([0]) for x in range(2, 2 * d, 2): for y in [0, 2 * d]: if hasq(x, y): - shapes.append(StabiliserShape('Z', G1, 2, [idq(x, y)], f"Z({x},{y})")) + shapes.append(StabiliserShape("Z", G1, 2, [idq(x, y)], f"Z({x},{y})")) for y in range(2, 2 * d, 2): for x in [0, 2 * d]: if hasq(x, y): - shapes.append(StabiliserShape('X', G1, 2, [idq(x, y)], f"X({x},{y})")) + shapes.append(StabiliserShape("X", G1, 2, [idq(x, y)], f"X({x},{y})")) base = BaseCode(num_qubits=qid, connectivity_graph=G, shapes=shapes) base.validate_local_connectivity() diff --git a/ACID/src/acid/codes/surface/unrotated_hex.py b/ACID/src/acid/codes/surface/unrotated_hex.py index 7619660..95e5388 100644 --- a/ACID/src/acid/codes/surface/unrotated_hex.py +++ b/ACID/src/acid/codes/surface/unrotated_hex.py @@ -1,16 +1,22 @@ from __future__ import annotations -from typing import Dict, List, Tuple +import itertools + import networkx as nx from acid.base_code import BaseCode, StabiliserShape def _path_template(n: int = 4) -> nx.Graph: - G = nx.Graph(); G.add_nodes_from(range(n)); [G.add_edge(i,i+1) for i in range(n-1)]; return G + G = nx.Graph() + G.add_nodes_from(range(n)) + [G.add_edge(i, i + 1) for i in range(n - 1)] + return G -def build_unrotated_surface_hex_code(d: int) -> Tuple[BaseCode, Dict[Tuple[int,int], int]]: +def build_unrotated_surface_hex_code( + d: int, +) -> tuple[BaseCode, dict[tuple[int, int], int]]: """ Distance-d unrotated surface (hex connectivity): - Grid size: W = H = 2d; coordinates in [0..2d-1]. One corner (W-1,H-1) is unused. @@ -27,107 +33,124 @@ def build_unrotated_surface_hex_code(d: int) -> Tuple[BaseCode, Dict[Tuple[int,i * X singles at virtual coords (x=2d+1, y=1,3,..,2d-1), implemented as single-qubit X on boundary qubits (W-1, y). Returns (G, stabs, coord_to_qid) without constructing a Code object. """ - W = 2 * d; H = 2 * d - coord_to_qid: Dict[Tuple[int,int], int] = {} - qlist: List[Tuple[int,int]] = [] + W = 2 * d + H = 2 * d + coord_to_qid: dict[tuple[int, int], int] = {} + qlist: list[tuple[int, int]] = [] qid = 0 for x in range(W): for y in range(H): - if x == W-1 and y == H-1: continue + if x == W - 1 and y == H - 1: + continue if (x % 2 == 0 and y % 2 == 0) or (x % 2 == 1 and y % 2 == 1): - coord_to_qid[(x,y)] = qid; qlist.append((x,y)); qid += 1 + coord_to_qid[(x, y)] = qid + qlist.append((x, y)) + qid += 1 + + def hasq(x: int, y: int) -> bool: + return (x, y) in coord_to_qid - def hasq(x:int,y:int)->bool: return (x,y) in coord_to_qid - def idq(x:int,y:int)->int: return coord_to_qid[(x,y)] + def idq(x: int, y: int) -> int: + return coord_to_qid[(x, y)] - G = nx.Graph(); G.add_nodes_from(range(len(qlist))) + G = nx.Graph() + G.add_nodes_from(range(len(qlist))) # E1 edges - for i in range(0, d): - for j in range(0, d): - if i == d-1 and j == d-1: continue - x1,y1 = 2*i, 2*j - x2,y2 = 2*i+1, 2*j+1 - if hasq(x1,y1) and hasq(x2,y2): G.add_edge(idq(x1,y1), idq(x2,y2)) + for i in range(d): + for j in range(d): + if i == d - 1 and j == d - 1: + continue + x1, y1 = 2 * i, 2 * j + x2, y2 = 2 * i + 1, 2 * j + 1 + if hasq(x1, y1) and hasq(x2, y2): + G.add_edge(idq(x1, y1), idq(x2, y2)) # E2 edges - for i in range(0, d): - for j in range(0, d): - x1,y1 = 2*i+1, 2*j+1 - x2,y2 = 2*i+2, 2*j - if hasq(x1,y1) and hasq(x2,y2): G.add_edge(idq(x1,y1), idq(x2,y2)) - - #E3 edges - for i in range(0, d): - for j in range(0, d): - x1,y1 = 2*i+1, 2*j+1 - x2,y2 = 2*i, 2*j+2 - if hasq(x1,y1) and hasq(x2,y2): G.add_edge(idq(x1,y1), idq(x2,y2)) - - shapes: List[StabiliserShape] = [] + for i in range(d): + for j in range(d): + x1, y1 = 2 * i + 1, 2 * j + 1 + x2, y2 = 2 * i + 2, 2 * j + if hasq(x1, y1) and hasq(x2, y2): + G.add_edge(idq(x1, y1), idq(x2, y2)) + + # E3 edges + for i in range(d): + for j in range(d): + x1, y1 = 2 * i + 1, 2 * j + 1 + x2, y2 = 2 * i, 2 * j + 2 + if hasq(x1, y1) and hasq(x2, y2): + G.add_edge(idq(x1, y1), idq(x2, y2)) + + shapes: list[StabiliserShape] = [] # X stabs (even, odd) — local path (k=3 boundary, k=4 bulk) - for i in range(0, d): - x = 2*i - for j in range(0, d-1): - y = 2*j+1 + for i in range(d): + x = 2 * i + for j in range(d - 1): + y = 2 * j + 1 u = hasq(x, y + 1) r = hasq(x + 1, y) down = hasq(x, y - 1) l = hasq(x - 1, y) - if (u and r and down and not l): + if u and r and down and not l: order = [(x, y + 1), (x + 1, y), (x, y - 1)] - elif (u and r and not down and l): + elif u and r and not down and l: order = [(x - 1, y), (x, y + 1), (x + 1, y)] - elif (u and not r and down and l): - order = [(x, y + 1), (x-1, y), (x, y-1)] - elif (not u and r and down and l): + elif u and not r and down and l: + order = [(x, y + 1), (x - 1, y), (x, y - 1)] + elif not u and r and down and l: order = [(x + 1, y), (x, y - 1), (x - 1, y)] else: - order = [(x-1, y), (x, y-1), (x+1, y), (x, y + 1)] + order = [(x - 1, y), (x, y - 1), (x + 1, y), (x, y + 1)] - for (x1, y1), (x2, y2) in zip(order[:1], order[1:]): + for (x1, y1), (x2, y2) in itertools.pairwise(order): if not G.has_edge(idq(x1, y1), idq(x2, y2)): - raise RuntimeError(f"Local stabiliser connectivity missing for X({x},{y}) between {(x1,y1)} and {(x2,y2)}") - path = _path_template(k := len(order)) + raise RuntimeError( + f"Local stabiliser connectivity missing for X({x},{y}) between {(x1, y1)} and {(x2, y2)}" + ) + path = _path_template(_k := len(order)) qmap = [idq(px, py) for (px, py) in order] - shapes.append(StabiliserShape('X', path, 2, qmap, f"X({x},{y})")) + shapes.append(StabiliserShape("X", path, 2, qmap, f"X({x},{y})")) # Z stabs (odd, even) — local path (k=3 or 4) - for i in range(0, d-1): - x = 2*i+1 - for j in range(0, d): - y = 2*j + for i in range(d - 1): + x = 2 * i + 1 + for j in range(d): + y = 2 * j u = hasq(x, y + 1) r = hasq(x + 1, y) down = hasq(x, y - 1) l = hasq(x - 1, y) - if (u and r and down and not l): + if u and r and down and not l: order = [(x, y + 1), (x + 1, y), (x, y - 1)] - elif (u and r and not down and l): + elif u and r and not down and l: order = [(x - 1, y), (x, y + 1), (x + 1, y)] - elif (u and not r and down and l): - order = [(x, y + 1), (x-1, y), (x, y-1)] - elif (not u and r and down and l): + elif u and not r and down and l: + order = [(x, y + 1), (x - 1, y), (x, y - 1)] + elif not u and r and down and l: order = [(x + 1, y), (x, y - 1), (x - 1, y)] else: order = [(x + 1, y), (x, y + 1), (x - 1, y), (x, y - 1)] for (x1, y1), (x2, y2) in zip(order[1:], order[:1]): if not G.has_edge(idq(x1, y1), idq(x2, y2)): - raise RuntimeError(f"Local stabiliser connectivity missing for Z({x},{y}) between {(x1,y1)} and {(x2,y2)}") - path = _path_template(k := len(order)) + raise RuntimeError( + f"Local stabiliser connectivity missing for Z({x},{y}) between {(x1, y1)} and {(x2, y2)}" + ) + path = _path_template(_k := len(order)) qmap = [idq(px, py) for (px, py) in order] - shapes.append(StabiliserShape('Z', path, 2, qmap, f"Z({x},{y})")) + shapes.append(StabiliserShape("Z", path, 2, qmap, f"Z({x},{y})")) # Boundary single-qubit stabilisers (no new edges) - G1 = nx.Graph(); G1.add_nodes_from([0]) + G1 = nx.Graph() + G1.add_nodes_from([0]) # Z singles along the top boundary: virtual y = H+1 (= 2d+1), odd x in [1..W-1] for x in range(1, W, 2): - if hasq(x, H-1): - q = idq(x, H-1) - shapes.append(StabiliserShape('Z', G1, 2, [q], f"Z({x},{H+1})")) + if hasq(x, H - 1): + q = idq(x, H - 1) + shapes.append(StabiliserShape("Z", G1, 2, [q], f"Z({x},{H + 1})")) # X singles along the right boundary: virtual x = W+1 (= 2d+1), odd y in [1..H-1] for y in range(1, H, 2): - if hasq(W-1, y): - q = idq(W-1, y) - shapes.append(StabiliserShape('X', G1, 2, [q], f"X({W+1},{y})")) + if hasq(W - 1, y): + q = idq(W - 1, y) + shapes.append(StabiliserShape("X", G1, 2, [q], f"X({W + 1},{y})")) base = BaseCode(num_qubits=len(qlist), connectivity_graph=G, shapes=shapes) base.validate_local_connectivity() diff --git a/ACID/src/acid/codes/toric/__init__.py b/ACID/src/acid/codes/toric/__init__.py index 3498379..1f866da 100644 --- a/ACID/src/acid/codes/toric/__init__.py +++ b/ACID/src/acid/codes/toric/__init__.py @@ -1,2 +1 @@ from .builder import build_toric_code - diff --git a/ACID/src/acid/codes/toric/builder.py b/ACID/src/acid/codes/toric/builder.py index 158ad00..bb486d3 100644 --- a/ACID/src/acid/codes/toric/builder.py +++ b/ACID/src/acid/codes/toric/builder.py @@ -1,11 +1,10 @@ from __future__ import annotations -from typing import List, Tuple import networkx as nx +from acid.base_code import BaseCode, StabiliserShape from acid.codes.bb.algebra import GroupRing, Monomial from acid.embedding import SquareGridEmbedding -from acid.base_code import BaseCode, StabiliserShape def _path_template(n: int = 4) -> nx.Graph: @@ -17,7 +16,9 @@ def _path_template(n: int = 4) -> nx.Graph: return G -def build_toric_code(l: int, m: int, *, connectivity: str = 'hex', sec_length: int = 2) -> Tuple[BaseCode, SquareGridEmbedding, List[Tuple[int,int,str]]]: +def build_toric_code( + l: int, m: int, *, connectivity: str = "hex", sec_length: int = 2 +) -> tuple[BaseCode, SquareGridEmbedding, list[tuple[int, int, str]]]: """ Build a toric code (periodic l×m) using two-term balanced-product definitions: @@ -37,15 +38,15 @@ def build_toric_code(l: int, m: int, *, connectivity: str = 'hex', sec_length: i emb = SquareGridEmbedding(ring=ring, pitch=1.0) # Monomials for shifts - a2 = Monomial(0, -1, ring) # y^-1 - a2_inv = a2.inv() # y - b2 = Monomial(-1, 0, ring) # x^-1 - b2_inv = b2.inv() # x + a2 = Monomial(0, -1, ring) # y^-1 + a2_inv = a2.inv() # y + b2 = Monomial(-1, 0, ring) # x^-1 + b2_inv = b2.inv() # x # Local shape for X and Z stabilisers: 4-node path path4 = _path_template(4) - shapes: List[StabiliserShape] = [] - connections: List[Tuple[int,int,str]] = [] + shapes: list[StabiliserShape] = [] + connections: list[tuple[int, int, str]] = [] for ax in range(l): for ay in range(m): @@ -55,36 +56,40 @@ def build_toric_code(l: int, m: int, *, connectivity: str = 'hex', sec_length: i # 1: R(b2 q) # 2: L(a2 q) # 3: R(q) - L_q = emb.qubit_id(*q.as_LR_tuple('L')) - R_b2q = emb.qubit_id(*((b2 * q).as_LR_tuple('R'))) - L_a2q = emb.qubit_id(*((a2 * q).as_LR_tuple('L'))) - R_q = emb.qubit_id(*q.as_LR_tuple('R')) + L_q = emb.qubit_id(*q.as_LR_tuple("L")) + R_b2q = emb.qubit_id(*((b2 * q).as_LR_tuple("R"))) + L_a2q = emb.qubit_id(*((a2 * q).as_LR_tuple("L"))) + R_q = emb.qubit_id(*q.as_LR_tuple("R")) # Order to ensure template path edges are present in device graph # 0-1: R(b2 q) — L(q) # 1-2: L(q) — R(q) # 2-3: R(q) — L(a2 q) x_map = [R_b2q, L_q, R_q, L_a2q] - shapes.append(StabiliserShape('X', path4, sec_length, x_map, f"X({ax},{ay})")) + shapes.append( + StabiliserShape("X", path4, sec_length, x_map, f"X({ax},{ay})") + ) # Z-stabiliser mapping order (use a2^-1, b2^-1 for connectivity): # 0: R(a2^-1 q) = R(y q) # 1: L(q) # 2: R(q) # 3: L(b2^-1 q) = L(x q) - R_a2invq = emb.qubit_id(*((a2_inv * q).as_LR_tuple('R'))) - L_b2invq = emb.qubit_id(*((b2_inv * q).as_LR_tuple('L'))) + R_a2invq = emb.qubit_id(*((a2_inv * q).as_LR_tuple("R"))) + L_b2invq = emb.qubit_id(*((b2_inv * q).as_LR_tuple("L"))) z_map = [R_a2invq, L_q, R_q, L_b2invq] - shapes.append(StabiliserShape('Z', path4, sec_length, z_map, f"Z({ax},{ay})")) + shapes.append( + StabiliserShape("Z", path4, sec_length, z_map, f"Z({ax},{ay})") + ) # Connectivity edges per anchor q: from L(q) to R( ... ) lq = L_q - connections.append((lq, R_q, 'ID')) - connections.append((lq, R_b2q, 'B2')) - connections.append((lq, R_a2invq, 'A2i')) - if connectivity.lower() in ('grid', 'grid4'): + connections.append((lq, R_q, "ID")) + connections.append((lq, R_b2q, "B2")) + connections.append((lq, R_a2invq, "A2i")) + if connectivity.lower() in ("grid", "grid4"): # Diagonal: R(a2^-1 b2 q) = R(y x^-1 q) - R_a2inv_b2_q = emb.qubit_id(*((a2_inv * b2 * q).as_LR_tuple('R'))) - connections.append((lq, R_a2inv_b2_q, 'A2iB2')) + R_a2inv_b2_q = emb.qubit_id(*((a2_inv * b2 * q).as_LR_tuple("R"))) + connections.append((lq, R_a2inv_b2_q, "A2iB2")) # Connectivity graph (undirected) ignores classes; edges are added between all pairs in connections G = nx.Graph() diff --git a/ACID/src/acid/defects/__init__.py b/ACID/src/acid/defects/__init__.py index abec8dc..7480473 100644 --- a/ACID/src/acid/defects/__init__.py +++ b/ACID/src/acid/defects/__init__.py @@ -1,2 +1 @@ """Defect handling: quasis, products, and scheduling.""" - diff --git a/ACID/src/acid/defects/defective_code.py b/ACID/src/acid/defects/defective_code.py index d90c982..dcfeb31 100644 --- a/ACID/src/acid/defects/defective_code.py +++ b/ACID/src/acid/defects/defective_code.py @@ -1,57 +1,69 @@ from __future__ import annotations -from typing import List, Tuple, Dict, Set +from collections.abc import Iterable from pathlib import Path -import numpy as np - +from typing import cast import networkx as nx +import numpy as np -from acid.defects.quasi import QuasiProduct, QuasiStabiliser from acid.base_code import BaseCode, StabiliserShape +from acid.defects.quasi import QuasiProduct, QuasiStabiliser from acid.defects.syndrome_extraction_circuit import SyndromeExtractionCircuit +from acid.device import DeviceVisualisation +from acid.embedding import Embedding +from acid.gf2_utils import ( + gf2_bidiagonalize, + gf2_is_in_span, + gf2_nullspace, + gf2_rank, + gf2_rank_normal_numpy, + gf2_rref_colwise, +) +from acid.pauli import AntiCommutingPauliBasis, CommutingPauliBasis, PauliString +from acid.scheduling.template_factory import TemplateFactory from acid.scheduling.types import StabiliserTemplate from acid.solver.schedule_solver import ScheduleSolver -from acid.scheduling.template_factory import TemplateFactory -from acid.device import DeviceVisualisation -from acid.embedding import Embedding -from acid.gf2_utils import gf2_rank, gf2_nullspace, gf2_bidiagonalize, gf2_rref_colwise, gf2_rref_numpy, gf2_is_in_span -from acid.pauli import PauliString, CommutingPauliBasis, AntiCommutingPauliBasis -def matmul_mod2_transpose(A: List[List[int]], B: List[List[int]]) -> List[List[int]]: +def matmul_mod2_transpose(A: list[list[int]], B: list[list[int]]) -> list[list[int]]: # A: r x n, B: s x n => A * B^T : r x s r = len(A) s = len(B) n = len(A[0]) if r else 0 - C = [[0]*s for _ in range(r)] + C = [[0] * s for _ in range(r)] for i in range(r): Ai = A[i] for j in range(s): acc = 0 Bj = B[j] for t in range(n): - acc ^= (Ai[t] & Bj[t]) + acc ^= Ai[t] & Bj[t] C[i][j] = acc & 1 return C -def build_quasi_stabilisers(base: BaseCode, dropped_qubits: Set[int], defective_edges: Set[Tuple[int,int]] | None = None) -> List[QuasiStabiliser]: - out: List[QuasiStabiliser] = [] +def build_quasi_stabilisers( + base: BaseCode, + dropped_qubits: set[int], + defective_edges: set[tuple[int, int]] | None = None, +) -> list[QuasiStabiliser]: + out: list[QuasiStabiliser] = [] # Normalize defective edges as undirected (min,max) - def_edges: Set[Tuple[int,int]] = set() + def_edges: set[tuple[int, int]] = set() if defective_edges: - def_edges = { (u,v) if u <= v else (v,u) for (u,v) in defective_edges } + def_edges = {(u, v) if u <= v else (v, u) for (u, v) in defective_edges} for shape in base.shapes: G = shape.connectivity_subgraph keep_nodes = [i for i in G.nodes if shape.qubit_map[i] not in dropped_qubits] if not keep_nodes: + # no qubits left in this stabiliser after dropout continue H = G.subgraph(keep_nodes).copy() # Remove edges whose mapped code-qubit pair is defective if def_edges: - to_remove: List[Tuple[int,int]] = [] - for (u0, v0) in H.edges(): + to_remove: list[tuple[int, int]] = [] + for u0, v0 in H.edges(): cu, cv = shape.qubit_map[u0], shape.qubit_map[v0] key = (cu, cv) if cu <= cv else (cv, cu) if key in def_edges: @@ -67,13 +79,13 @@ def build_quasi_stabilisers(base: BaseCode, dropped_qubits: Set[int], defective_ support=support, parent=shape, component_index=comp_idx, - label = f"{shape.label}_c{comp_idx}" + label=f"{shape.label}_c{comp_idx}", ) ) return out -def build_anticommutation_graph(quasi_stabs: List[QuasiStabiliser]) -> nx.Graph: +def build_anticommutation_graph(quasi_stabs: list[QuasiStabiliser]) -> nx.Graph: """Return anti-commutation graph with label-nodes and 'quasi' attributes. Nodes are quasi labels (strings). Each node stores the QuasiStabiliser as @@ -95,16 +107,26 @@ def build_anticommutation_graph(quasi_stabs: List[QuasiStabiliser]) -> nx.Graph: G.remove_nodes_from(isolates) return G + class DefectiveCode: """ Centralized workflow for handling dropouts: builds quasi-stabilisers, anti-commutation graph, SVD-based products, and synthesizes a schedule. """ - def __init__(self, code: BaseCode, dropped_nodes: List[int] | Set[int] = (), dropped_edges: List[Tuple[int,int]] = (), *, verify: bool = True) -> None: + def __init__( + self, + code: BaseCode, + dropped_nodes: list[int] | set[int] | tuple[int, ...] = (), + dropped_edges: list[tuple[int, int]] | tuple[tuple[int, int], ...] = (), + *, + verify: bool = True, + ) -> None: self.base_code = code - self.dropped_nodes: Set[int] = set(int(q) for q in dropped_nodes) - self.dropped_edges: List[Tuple[int,int]] = [(int(u), int(v)) for (u, v) in dropped_edges] + self.dropped_nodes: set[int] = {int(q) for q in dropped_nodes} + self.dropped_edges: list[tuple[int, int]] = [ + (int(u), int(v)) for (u, v) in dropped_edges + ] self.num_qubits = self.base_code.num_qubits - len(self.dropped_nodes) self.solver = None # type: ScheduleSolver | None @@ -114,49 +136,67 @@ def __init__(self, code: BaseCode, dropped_nodes: List[int] | Set[int] = (), dro # Build a connectivity graph that excludes dropped edges entirely self.connectivity_graph = nx.Graph() self.connectivity_graph.add_nodes_from(self.base_code.connectivity_graph.nodes) - dropped_norm = {(min(int(u), int(v)), max(int(u), int(v))) for (u, v) in self.dropped_edges} + dropped_norm = { + (min(int(u), int(v)), max(int(u), int(v))) for (u, v) in self.dropped_edges + } for u, v, data in self.base_code.connectivity_graph.edges(data=True): a, b = (int(u), int(v)) if int(u) <= int(v) else (int(v), int(u)) if (a, b) in dropped_norm: continue - self.connectivity_graph.add_edge(u, v, **{k: v for k, v in data.items() if k != 'defective'}) + self.connectivity_graph.add_edge( + u, v, **{k: v for k, v in data.items() if k != "defective"} + ) # Step 1: build quasis # Normalize dropped edges as undirected pairs - def_edges_norm: Set[Tuple[int,int]] = set() - for (u, v) in self.dropped_edges: + def_edges_norm: set[tuple[int, int]] = set() + for u, v in self.dropped_edges: a, b = (int(u), int(v)) def_edges_norm.add((a, b) if a <= b else (b, a)) - self.all_quasis: List[QuasiStabiliser] = build_quasi_stabilisers(self.base_code, self.dropped_nodes, defective_edges=def_edges_norm) - self.x_quasis = [quasi for quasi in self.all_quasis if quasi.pauli_type=='X'] - self.z_quasis = [quasi for quasi in self.all_quasis if quasi.pauli_type=='Z'] + self.all_quasis: list[QuasiStabiliser] = build_quasi_stabilisers( + self.base_code, self.dropped_nodes, defective_edges=def_edges_norm + ) + self.x_quasis = [quasi for quasi in self.all_quasis if quasi.pauli_type == "X"] + self.z_quasis = [quasi for quasi in self.all_quasis if quasi.pauli_type == "Z"] # Labels for consistency across modules - self.quasi_labels: List[str] = [q.label for q in self.all_quasis] + self.quasi_labels: list[str] = [q.label for q in self.all_quasis] # Step 2: anticomm graph (pruned, label-noded) self.anticomm_graph = build_anticommutation_graph(self.all_quasis) - self.nontrivial_idx: Set[str] = set(self.anticomm_graph.nodes()) + self.nontrivial_idx: set[str] = set(self.anticomm_graph.nodes()) # Convenience maps - self.label_to_quasi: Dict[str, QuasiStabiliser] = {q.label: q for q in self.all_quasis} + self.label_to_quasi: dict[str, QuasiStabiliser] = { + q.label: q for q in self.all_quasis + } # Also create one-hot quasis for dropped qubits (kept separate from anticomm graph) - self.dropped_qubit_quasis: Dict[str, QuasiStabiliser] = self._build_dropped_quasis() + self.dropped_qubit_quasis: dict[str, QuasiStabiliser] = ( + self._build_dropped_quasis() + ) self.label_to_quasi.update(self.dropped_qubit_quasis) # Step 3: Derive product stabilisers and gauge operators from the # anticommutation graph (bipartite Z-X) via GF(2) diagonalization. # Build a labeled anticommutation graph using quasi labels self._compute_diag_from_anticomm() - self.products: List[QuasiProduct] = self._build_products() + self.products: list[QuasiProduct] = self._build_products() # Store base stabiliser matrices HX/HZ at base width n for reuse _hx_supp, _hz_supp = self._stabiliser_supports() n_base = self.base_code.num_qubits - self.HX: List[List[int]] = self._rows_to_matrix(_hx_supp, n_base) - self.HZ: List[List[int]] = self._rows_to_matrix(_hz_supp, n_base) - self.gauges: List[Tuple[QuasiProduct, QuasiProduct]] = self._build_gauges() + # stabiliser matrices + self.HX: list[list[int]] = self._rows_to_matrix(_hx_supp, n_base) + self.HZ: list[list[int]] = self._rows_to_matrix(_hz_supp, n_base) + self.gauges: list[tuple[QuasiProduct | None, QuasiProduct | None]] = ( + self._build_gauges() + ) # Also store gauge matrices GX/GZ directly from gauges (includes one-hot drop gauges) - def _xor_supports_labels(members: List[str]) -> List[int]: - acc: Set[int] = set() + # so if there is a dropped qubit, the corresponding one-hot gauge is included in GX/GZ. + # and multiply any gauge + def _xor_supports_labels(members: list[str]) -> list[int]: + """XOR the supports of the given quasis by their labels. + + Returns the sorted list of qubit indices in the XORed support.""" + acc: set[int] = set() for lab in members: q = self.label_to_quasi.get(lab) if q is None: @@ -164,8 +204,10 @@ def _xor_supports_labels(members: List[str]) -> List[int]: s = set(q.support) acc = (acc - s) | (s - acc) return sorted(acc) - GX_mat: List[List[int]] = [] - GZ_mat: List[List[int]] = [] + + GX_mat: list[list[int]] = [] + GZ_mat: list[list[int]] = [] + # Constructs gauge matrices GX and GZ from the quasi products in self.gauges. for zg, xg in self.gauges: if xg is not None: if xg.members: @@ -176,10 +218,13 @@ def _xor_supports_labels(members: List[str]) -> List[int]: if 0 <= q < n_base: row[q] ^= 1 GX_mat.append(row) + # Adds one-hot rows for dropped qubits to GX matrix if the quasi product is a + # drop gauge. elif xg.label.startswith("QgX_drop_"): q = int(xg.label.split("QgX_drop_")[-1]) if 0 <= q < n_base: - row = [0] * n_base; row[q] = 1 + row = [0] * n_base + row[q] = 1 GX_mat.append(row) if zg is not None: if zg.members: @@ -193,10 +238,15 @@ def _xor_supports_labels(members: List[str]) -> List[int]: elif zg.label.startswith("QgZ_drop_"): q = int(zg.label.split("QgZ_drop_")[-1]) if 0 <= q < n_base: - row = [0] * n_base; row[q] = 1 + row = [0] * n_base + row[q] = 1 GZ_mat.append(row) - self.GX: List[List[int]] = GX_mat - self.GZ: List[List[int]] = GZ_mat + # gauge matrices (may be empty if no gauges) + self.GX: list[list[int]] = GX_mat + self.GZ: list[list[int]] = GZ_mat + + print(GX_mat) + print(GZ_mat) # Stabiliser triplets (templates/qubit maps) for all quasis self.triplets = self._reify_quasi_templates() @@ -207,15 +257,15 @@ def _xor_supports_labels(members: List[str]) -> List[int]: if verify: self._verify_logicals_and_gauges() - - def logical_rows_2n(self) -> Tuple[List[List[int]], List[List[int]]]: + def logical_rows_2n(self) -> tuple[list[list[int]], list[list[int]]]: """ Return paired logical rows in 2n format [X|Z] over GF(2). Rows are ordered so that i-th X row anticommutes with i-th Z row. """ n = self.base_code.num_qubits - def vec2n_from_supports(Xs: List[int], Zs: List[int]) -> List[int]: + + def vec2n_from_supports(Xs: list[int], Zs: list[int]) -> list[int]: X = [0] * n Z = [0] * n for q in Xs: @@ -225,8 +275,9 @@ def vec2n_from_supports(Xs: List[int], Zs: List[int]) -> List[int]: if 0 <= q < n: Z[q] ^= 1 return X + Z - Lx_2n: List[List[int]] = [] - Lz_2n: List[List[int]] = [] + + Lx_2n: list[list[int]] = [] + Lz_2n: list[list[int]] = [] for xs, zs in zip(self.logical_X_rows, self.logical_Z_rows): Lx_2n.append(vec2n_from_supports(xs, [])) Lz_2n.append(vec2n_from_supports([], zs)) @@ -234,26 +285,33 @@ def vec2n_from_supports(Xs: List[int], Zs: List[int]) -> List[int]: def midcycle_untouched_stabilisers(self) -> CommutingPauliBasis: # Base-code stabilisers (un-products) - x_supps: List[List[int]] = [] - z_supps: List[List[int]] = [] + x_supps: list[list[int]] = [] + z_supps: list[list[int]] = [] for label in self.quasi_labels: if label in self.nontrivial_idx: continue stab = self.label_to_quasi[label] supp = list(stab.support) - if stab.parent.pauli_type == 'X': + if stab.pauli_type == "X": x_supps.append(supp) else: z_supps.append(supp) - return CommutingPauliBasis.from_supports(name="MidCycle/Base", priority=10, x_supports=x_supps, z_supports=z_supps, n=self.base_code.num_qubits) + return CommutingPauliBasis.from_supports( + name="MidCycle/Base", + priority=10, + x_supports=x_supps, + z_supports=z_supps, + n=self.base_code.num_qubits, + ) def midcycle_product_stabilisers(self) -> CommutingPauliBasis | None: # Products derived from quasi SVD if not self.products: return None - label_to_quasi: Dict[str, QuasiStabiliser] = self.label_to_quasi - def xor_supports(members: List[str]) -> List[int]: - acc: Set[int] = set() + label_to_quasi: dict[str, QuasiStabiliser] = self.label_to_quasi + + def xor_supports(members: list[str]) -> list[int]: + acc: set[int] = set() for lab in members: q = label_to_quasi.get(lab) if q is None: @@ -261,41 +319,59 @@ def xor_supports(members: List[str]) -> List[int]: s = set(q.support) acc = (acc - s) | (s - acc) return sorted(acc) - x_supps: List[List[int]] = [] - z_supps: List[List[int]] = [] + + x_supps: list[list[int]] = [] + z_supps: list[list[int]] = [] for ps in self.products: supp = xor_supports(ps.members) if not supp: continue - if ps.pauli_type == 'X': + if ps.pauli_type == "X": x_supps.append(supp) else: z_supps.append(supp) if not x_supps and not z_supps: return None - return CommutingPauliBasis.from_supports(name="Products", priority=0, x_supports=x_supps, z_supports=z_supps, n=self.base_code.num_qubits) + return CommutingPauliBasis.from_supports( + name="Products", + priority=0, + x_supports=x_supps, + z_supports=z_supps, + n=self.base_code.num_qubits, + ) - def _logical_pairs_mid_paulis(self) -> Tuple[List[PauliString], List[PauliString]]: + def _logical_pairs_mid_paulis(self) -> tuple[list[PauliString], list[PauliString]]: n = self.base_code.num_qubits Lx = [PauliString.from_supports(xs, [], n) for xs in self.logical_X_rows] Lz = [PauliString.from_supports([], zs, n) for zs in self.logical_Z_rows] return Lx, Lz - - def _gauge_pairs_mid_paulis(self) -> Tuple[List[PauliString], List[PauliString]]: + + def _gauge_pairs_mid_paulis(self) -> tuple[list[PauliString], list[PauliString]]: n = self.base_code.num_qubits # Build directly from stored gauge matrices (includes drop one-hots) - Gx_ps = [PauliString.from_supports([i for i, b in enumerate(row) if b & 1], [], n) for row in self.GX] - Gz_ps = [PauliString.from_supports([], [i for i, b in enumerate(row) if b & 1], n) for row in self.GZ] + Gx_ps = [ + PauliString.from_supports([i for i, b in enumerate(row) if b & 1], [], n) + for row in self.GX + ] + Gz_ps = [ + PauliString.from_supports([], [i for i, b in enumerate(row) if b & 1], n) + for row in self.GZ + ] return Gx_ps, Gz_ps def logical_pairs_mid(self) -> AntiCommutingPauliBasis: Lx, Lz = self._logical_pairs_mid_paulis() return AntiCommutingPauliBasis(name="Lmid", X_rows=Lx, Z_rows=Lz) + def _reify_quasi_templates(self) -> list[tuple[StabiliserTemplate, list[int], str]]: + """Reify a stabiliser template for each quasi stabiliser in self.all_quasis. + + Concatenates the qubit map from the parent stabiliser shape with the + relabelled connectivity subgraph of the quasi's support. - def _reify_quasi_templates(self) -> List[Tuple[StabiliserTemplate, List[int], str]]: + Returns a list of triplets (template, qubit_map, label) for each quasi.""" tf = TemplateFactory() - triplets: List[Tuple[StabiliserTemplate, List[int], str]] = [] + triplets: list[tuple[StabiliserTemplate, list[int], str]] = [] for i, q in enumerate(self.all_quasis): shape: StabiliserShape = q.parent # type: ignore[assignment] G = shape.connectivity_subgraph @@ -305,14 +381,14 @@ def _reify_quasi_templates(self) -> List[Tuple[StabiliserTemplate, List[int], st H0 = G.subgraph(kept_old).copy() H = nx.Graph() H.add_nodes_from(H0.nodes()) - for (u0, v0) in H0.edges(): + for u0, v0 in H0.edges(): cu, cv = shape.qubit_map[u0], shape.qubit_map[v0] if self.connectivity_graph.has_edge(cu, cv): H.add_edge(u0, v0) old_to_new = {old: new for new, old in enumerate(sorted(H.nodes()))} relabelled = nx.Graph() relabelled.add_nodes_from(range(len(old_to_new))) - for (u0, v0) in H.edges(): + for u0, v0 in H.edges(): relabelled.add_edge(old_to_new[u0], old_to_new[v0]) SEC_len = int(shape.sec_cycle_length) # Always pass through preferences/hints (even if damaged); they will only mark schedules preferred when applicable. @@ -327,91 +403,147 @@ def _reify_quasi_templates(self) -> List[Tuple[StabiliserTemplate, List[int], st schedule_hint=shape.schedule_hint, layer_hint=shape.layer_hint, ) - qubit_map = [shape.qubit_map[old] for old in sorted(old_to_new.keys(), key=lambda x: old_to_new[x])] + qubit_map = [ + shape.qubit_map[old] + for old in sorted(old_to_new.keys(), key=lambda x: old_to_new[x]) + ] triplets.append((new_tmpl, qubit_map, q.label)) return triplets - def _build_products(self) -> List[QuasiProduct]: - products: List[QuasiProduct] = [] + def _build_products(self) -> list[QuasiProduct]: + products: list[QuasiProduct] = [] # Z products are rows i >= r (over Z-side basis self.z_anti_qs) for i in range(self.r, len(self.U)): coeffs = self.U[i] - members = [self.z_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1] + members = [ + self.z_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1 + ] if members: - products.append(QuasiProduct(label=f"QpZ_{i}", pauli_type='Z', members=members)) + products.append( + QuasiProduct(label=f"QpZ_{i}", pauli_type="Z", members=members) + ) # X products are rows i >= r in VT (over X-side basis self.x_anti_qs) for i in range(self.r, len(self.VT)): coeffs = self.VT[i] - members = [self.x_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1] + members = [ + self.x_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1 + ] if members: - products.append(QuasiProduct(label=f"QpX_{i}", pauli_type='X', members=members)) + products.append( + QuasiProduct(label=f"QpX_{i}", pauli_type="X", members=members) + ) return products - - def _build_dropped_quasis(self) -> Dict[str, QuasiStabiliser]: + + def _build_dropped_quasis(self) -> dict[str, QuasiStabiliser]: """Create one-hot quasi stabilisers for each dropped qubit (X and Z type). These are not included in the anticomm graph or scheduling, but allow treating dropped-qubit gauges uniformly as products over quasi labels. """ - out: Dict[str, QuasiStabiliser] = {} + out: dict[str, QuasiStabiliser] = {} import networkx as nx + n = self.base_code.num_qubits if not self.dropped_nodes: return out - G1 = nx.Graph(); G1.add_nodes_from([0]) + G1 = nx.Graph() + G1.add_nodes_from([0]) for qq in sorted(int(q) for q in self.dropped_nodes): if not (0 <= qq < n): continue # X one-hot - shx = StabiliserShape('X', G1, 1, [qq], f"DropX({qq})") - qx = QuasiStabiliser(pauli_type='X', support=frozenset({qq}), parent=shx, component_index=0, label=shx.label) + shx = StabiliserShape("X", G1, 1, [qq], f"DropX({qq})") + qx = QuasiStabiliser( + pauli_type="X", + support=frozenset({qq}), + parent=shx, + component_index=0, + label=shx.label, + ) out[qx.label] = qx # Z one-hot - shz = StabiliserShape('Z', G1, 1, [qq], f"DropZ({qq})") - qz = QuasiStabiliser(pauli_type='Z', support=frozenset({qq}), parent=shz, component_index=0, label=shz.label) + shz = StabiliserShape("Z", G1, 1, [qq], f"DropZ({qq})") + qz = QuasiStabiliser( + pauli_type="Z", + support=frozenset({qq}), + parent=shz, + component_index=0, + label=shz.label, + ) out[qz.label] = qz return out - - def _build_gauges(self) -> List[Tuple[QuasiProduct, QuasiProduct]]: - gauges: List[Tuple[QuasiProduct, QuasiProduct]] = [] + + def _build_gauges(self) -> list[tuple[QuasiProduct | None, QuasiProduct | None]]: + gauges: list[tuple[QuasiProduct | None, QuasiProduct | None]] = [] # Z gauges are rows i < r from U (Z space) for i in range(self.r): coeffs = self.U[i] - members = [self.z_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1] + members = [ + self.z_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1 + ] if members: - gauges.append((QuasiProduct(label=f"QgZ_{i}", pauli_type='Z', members=members), None)) + gauges.append( + ( + QuasiProduct(label=f"QgZ_{i}", pauli_type="Z", members=members), + None, + ) + ) # X gauges are rows i < r from VT (X space) - for i in range(self.r): + for i in range(self.r): coeffs = self.VT[i] - members = [self.x_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1] + members = [ + self.x_anti_qs[k].label for k, bit in enumerate(coeffs) if bit & 1 + ] if members: if i < len(gauges) and gauges[i][1] is None: - gauges[i] = (gauges[i][0], QuasiProduct(label=f"QgX_{i}", pauli_type='X', members=members)) + gauges[i] = ( + gauges[i][0], + QuasiProduct(label=f"QgX_{i}", pauli_type="X", members=members), + ) else: - gauges.append((None, QuasiProduct(label=f"QgX_{i}", pauli_type='X', members=members))) + gauges.append( + ( + None, + QuasiProduct( + label=f"QgX_{i}", pauli_type="X", members=members + ), + ) + ) # Add one-hot gauge pairs for dropped qubits if not in span of HX/HZ if self.dropped_nodes: n = self.base_code.num_qubits for q in sorted(int(q) for q in self.dropped_nodes): if 0 <= q < n: - ex = [0] * n; ex[q] = 1 - ez = [0] * n; ez[q] = 1 - if not gf2_is_in_span(ex, self.HX) and not gf2_is_in_span(ez, self.HZ): + ex = [0] * n + ex[q] = 1 + ez = [0] * n + ez[q] = 1 + if not gf2_is_in_span(ex, self.HX) and not gf2_is_in_span( + ez, self.HZ + ): # Add as proper member-labelled gauge qubit pair - zg = QuasiProduct(label=f"QgZ_drop_{q}", pauli_type='Z', members=[f"DropZ({q})"]) - xg = QuasiProduct(label=f"QgX_drop_{q}", pauli_type='X', members=[f"DropX({q})"]) + zg = QuasiProduct( + label=f"QgZ_drop_{q}", + pauli_type="Z", + members=[f"DropZ({q})"], + ) + xg = QuasiProduct( + label=f"QgX_drop_{q}", + pauli_type="X", + members=[f"DropX({q})"], + ) gauges.append((zg, xg)) return gauges - - def _compute_diag_from_anticomm(self) -> Dict: + def _compute_diag_from_anticomm(self) -> None: # Build bipartite sets and adjacency matrix A (Z rows, X cols) - nodes = list(nx.get_node_attributes(self.anticomm_graph, 'quasi').values()) - self.x_anti_qs = [q for q in nodes if q.pauli_type == 'X'] - self.z_anti_qs = [q for q in nodes if q.pauli_type == 'Z'] - ZN = len(self.z_anti_qs); XN = len(self.x_anti_qs) + nodes = list(nx.get_node_attributes(self.anticomm_graph, "quasi").values()) + self.x_anti_qs = [q for q in nodes if q.pauli_type == "X"] + self.z_anti_qs = [q for q in nodes if q.pauli_type == "Z"] + ZN = len(self.z_anti_qs) + XN = len(self.x_anti_qs) x_lookup = {q_x.label: i for i, q_x in enumerate(self.x_anti_qs)} - self.A: List[List[int]] = [[0]*XN for _ in range(ZN)] + self.A: list[list[int]] = [[0] * XN for _ in range(ZN)] for i, zl in enumerate(self.z_anti_qs): for nbr_label in self.anticomm_graph.neighbors(zl.label): j = x_lookup[nbr_label] @@ -420,9 +552,7 @@ def _compute_diag_from_anticomm(self) -> Dict: # X coefficients as rows of V^T self.VT = [list(row) for row in zip(*V)] if V else [] - - - def _stabiliser_supports(self) -> Tuple[List[List[int]], List[List[int]]]: + def _stabiliser_supports(self) -> tuple[list[list[int]], list[list[int]]]: """Return (X_rows, Z_rows) stabiliser supports (as lists of qubit ids). Uses isolate quasi-stabilisers (post-dropout components that do not @@ -430,28 +560,30 @@ def _stabiliser_supports(self) -> Tuple[List[List[int]], List[List[int]]]: inferred from the anticommutation graph diagonalisation. This ensures supports reflect post-dropout connectivity (e.g., boundary 4->3). """ - x_rows: List[List[int]] = [] - z_rows: List[List[int]] = [] + x_rows: list[list[int]] = [] + z_rows: list[list[int]] = [] # Add isolate quasis (labels not present in the anticomm graph after pruning) - label_to_quasi: Dict[str, QuasiStabiliser] = {q.label: q for q in self.all_quasis} + label_to_quasi: dict[str, QuasiStabiliser] = { + q.label: q for q in self.all_quasis + } for label in self.quasi_labels: if label in self.nontrivial_idx: continue q = label_to_quasi.get(label) if q is None: continue - supp = sorted(list(q.support)) + supp = sorted(q.support) if not supp: continue - if q.pauli_type == 'X': + if q.pauli_type == "X": x_rows.append(supp) else: z_rows.append(supp) # Add product stabilisers derived from quasis - def xor_supports_labels(members: List[str]) -> List[int]: - acc: Set[int] = set() + def xor_supports_labels(members: list[str]) -> list[int]: + acc: set[int] = set() for lab in members: q = label_to_quasi.get(lab) if q is None: @@ -464,17 +596,19 @@ def xor_supports_labels(members: List[str]) -> List[int]: supp = xor_supports_labels(ps.members) if not supp: continue - if ps.pauli_type == 'X': + if ps.pauli_type == "X": x_rows.append(supp) else: z_rows.append(supp) + # Reduce to independent sets to avoid dependent SX/SZ - def reduce_independent(rows: List[List[int]], n: int) -> List[List[int]]: - M: List[List[int]] = [] - keep: List[List[int]] = [] + # SX is [HX; GX] and SZ is [HZ; GZ]; we want to avoid dependent rows in either. + def reduce_independent(rows: list[list[int]], n: int) -> list[list[int]]: + M: list[list[int]] = [] + keep: list[list[int]] = [] r = 0 for supp in rows: - vec = [0]*n + vec = [0] * n for q in supp: if 0 <= int(q) < n: vec[int(q)] ^= 1 @@ -483,14 +617,14 @@ def reduce_independent(rows: List[List[int]], n: int) -> List[List[int]]: keep.append(supp) r += 1 return keep + n = self.base_code.num_qubits x_rows = reduce_independent(x_rows, n) z_rows = reduce_independent(z_rows, n) return x_rows, z_rows - - def _rows_to_matrix(self, rows: List[List[int]], n: int) -> List[List[int]]: - M: List[List[int]] = [] + def _rows_to_matrix(self, rows: list[list[int]], n: int) -> list[list[int]]: + M: list[list[int]] = [] for supp in rows: vec = [0] * n for q in supp: @@ -500,14 +634,12 @@ def _rows_to_matrix(self, rows: List[List[int]], n: int) -> List[List[int]]: M.append(vec) return M - - - def _compute_logical_rows(self) -> Tuple[List[List[int]], List[List[int]]]: + def _compute_logical_rows(self) -> tuple[list[list[int]], list[list[int]]]: """Explicit construction of logical operators per the stated recipe. 1) Build SZ = [HZ; GZ] and SX = [HX; GX] at base width n, assert full row rank. - 2) RREF SX, SZ; form nullspaces NX = Null(SZ), NZ = Null(SX). - 3) CX = [SX; NZ], CZ = [SZ; NX]; RREF both; the first m rows are independent; the + 2) RREF SX, SZ; form nullspaces NX = Null(SX), NZ = Null(SZ). + 3) CX = [HX; NZ], CZ = [HZ; NX]; RREF both; the first m rows are independent; the remaining k = n_eff - 2*rank(HX) - rank(GX) non-zero rows are logicals (Z from CX, X from CZ). 4) Pair the k X/Z logicals via bidiagonalization. """ @@ -527,9 +659,13 @@ def _compute_logical_rows(self) -> Tuple[List[List[int]], List[List[int]]]: rank_SX = gf2_rank(SX) rank_SZ = gf2_rank(SZ) if rank_SX != len(SX): - raise AssertionError(f"SX has dependent rows (rank={rank_SX}, rows={len(SX)})") + raise AssertionError( + f"SX has dependent rows (rank={rank_SX}, rows={len(SX)})" + ) if rank_SZ != len(SZ): - raise AssertionError(f"SZ has dependent rows (rank={rank_SZ}, rows={len(SZ)})") + raise AssertionError( + f"SZ has dependent rows (rank={rank_SZ}, rows={len(SZ)})" + ) # Step 2: RREF (for structure) and nullspaces (no column permutations) NZ = gf2_nullspace(SZ) # X-candidates that commute with SZ @@ -538,9 +674,14 @@ def _compute_logical_rows(self) -> Tuple[List[List[int]], List[List[int]]]: # Step 3: Stack, RREF, and extract logical rows beyond first m CX = HX + NZ CZ = HZ + NX - CX_rref, _ = gf2_rref_colwise(CX, clear_upper_triangle=False) - CZ_rref, _ = gf2_rref_colwise(CZ, clear_upper_triangle=False) - + CX_rref, _ = cast( + tuple[list[list[int]], list[int]], + gf2_rref_colwise(CX, clear_upper_triangle=False), + ) + CZ_rref, _ = cast( + tuple[list[list[int]], list[int]], + gf2_rref_colwise(CZ, clear_upper_triangle=False), + ) # Compute expected k and verify number of non-zero tail rows rank_HX = gf2_rank(HX) @@ -557,8 +698,9 @@ def _compute_logical_rows(self) -> Tuple[List[List[int]], List[List[int]]]: if not any(CZ_rref[i]): raise AssertionError("First m rows of CZ_rref not independent") - def tail_non_zero_rows(R: List[List[int]], start: int) -> List[List[int]]: + def tail_non_zero_rows(R: list[list[int]], start: int) -> list[list[int]]: return [row for row in R[start:] if any(row)] + tail_CX = tail_non_zero_rows(CX_rref, rank_HX) # these define Z logicals tail_CZ = tail_non_zero_rows(CZ_rref, rank_HZ) # these define X logicals if len(tail_CX) != k_expected or len(tail_CZ) != k_expected: @@ -571,11 +713,20 @@ def tail_non_zero_rows(R: List[List[int]], start: int) -> List[List[int]]: # Step 4: Pair X/Z logicals (make them anti-commute in matched pairs) C = matmul_mod2_transpose(X_rows, Z_rows) - _, U, _, V_T, _, r = gf2_rref_numpy(np.array(C)) - def apply_transform(T: List[List[int]], Rows: List[List[int]]) -> List[List[int]]: + _, U, _, V_T, _, _r = gf2_rank_normal_numpy(np.array(C)) + + # U, V, r = gf2_bidiagonalize(C) + # V = np.array(V, dtype=np.int8).tolist() + + def apply_transform( + T: list[list[int]], Rows: list[list[int]] + ) -> list[list[int]]: + """Apply a GF(2) transformation T to a list of row vectors Rows, + returning the transformed rows. + """ if not Rows: return [] - out: List[List[int]] = [] + out: list[list[int]] = [] for coeffs in T: vec = [0] * len(Rows[0]) for idx, bit in enumerate(coeffs): @@ -584,10 +735,12 @@ def apply_transform(T: List[List[int]], Rows: List[List[int]]) -> List[List[int] out.append(vec) return out - Xp = apply_transform(U, X_rows) - Zp = apply_transform(V_T.T, Z_rows) + U_list: list[list[int]] = np.asarray(U, dtype=np.int8).tolist() + VtT_list: list[list[int]] = np.asarray(V_T.T, dtype=np.int8).tolist() + Xp = apply_transform(U_list, X_rows) + Zp = apply_transform(VtT_list, Z_rows) - def vec_to_support(v: List[int]) -> List[int]: + def vec_to_support(v: list[int]) -> list[int]: return [i for i, b in enumerate(v) if b & 1] X_supports = [vec_to_support(Xp[i]) for i in range(min(k_expected, len(Xp)))] @@ -602,7 +755,7 @@ def _verify_logicals_and_gauges(self) -> None: - Uses a single stacked product C = [Lx; Gx] * [Lz; Gz]^T over GF(2). """ n = self.base_code.num_qubits - n_eff = n - len(self.dropped_nodes) + n - len(self.dropped_nodes) # Build Pauli representations Lx_ps, Lz_ps = self._logical_pairs_mid_paulis() @@ -623,9 +776,10 @@ def _verify_logicals_and_gauges(self) -> None: raise AssertionError(f"Gauge Z[{i}] has non-zero X part") # Convert PauliStrings to row matrices over base n - def rows_from_X(ps: List[PauliString]) -> List[List[int]]: + def rows_from_X(ps: list[PauliString]) -> list[list[int]]: return [row.X[:] for row in ps] - def rows_from_Z(ps: List[PauliString]) -> List[List[int]]: + + def rows_from_Z(ps: list[PauliString]) -> list[list[int]]: return [row.Z[:] for row in ps] Lx = rows_from_X(Lx_ps) @@ -660,14 +814,20 @@ def rows_from_Z(ps: List[PauliString]) -> List[List[int]]: # Expected block-diagonal identity: diag(I_k, I_g) k = kx g = gx + # Helper to check identity and zero blocks - def check_block_is_identity(mat: List[List[int]], r0: int, c0: int, sz: int, label: str) -> None: + def check_block_is_identity( + mat: list[list[int]], r0: int, c0: int, sz: int, label: str + ) -> None: for i in range(sz): for j in range(sz): exp = 1 if i == j else 0 if mat[r0 + i][c0 + j] != exp: raise AssertionError(f"{label} block not identity at ({i},{j})") - def check_block_is_zero(mat: List[List[int]], r0: int, c0: int, rsz: int, csz: int, label: str) -> None: + + def check_block_is_zero( + mat: list[list[int]], r0: int, c0: int, rsz: int, csz: int, label: str + ) -> None: for i in range(rsz): for j in range(csz): if mat[r0 + i][c0 + j] != 0: @@ -676,7 +836,9 @@ def check_block_is_zero(mat: List[List[int]], r0: int, c0: int, rsz: int, csz: i # Expect exactly k = n - rank(Sx_full) - rank(Sz_full) logical pairs (using base n) k_expected = max(0, n - gf2_rank(Sx) - gf2_rank(Sz) - gf2_rank(Gx)) if kx != k_expected or kz != k_expected: - raise AssertionError(f"Unexpected logical count: kx={kx}, kz={kz}, expected={k_expected}") + raise AssertionError( + f"Unexpected logical count: kx={kx}, kz={kz}, expected={k_expected}" + ) # Top-left: logicals vs logicals check_block_is_identity(C, 0, 0, k, "Logical") @@ -697,10 +859,10 @@ def check_block_is_zero(mat: List[List[int]], r0: int, c0: int, rsz: int, csz: i check_block_is_zero(C, k + g, k, sx, g, "Stabiliser-X/Gauge cross") # Public API - def stats(self) -> Dict: + def stats(self) -> dict: rank = self.r - num_qpz = sum(1 for p in self.products if p.pauli_type == 'Z') - num_qpx = sum(1 for p in self.products if p.pauli_type == 'X') + num_qpz = sum(1 for p in self.products if p.pauli_type == "Z") + num_qpx = sum(1 for p in self.products if p.pauli_type == "X") # Anticommutation graph stats try: num_anticomm_nodes = len(list(self.anticomm_graph.nodes())) @@ -709,29 +871,35 @@ def stats(self) -> Dict: num_anticomm_nodes = len(self.nontrivial_idx) num_anticomm_edges = 0 # Gauge counts (including drop gauges) - gauges = getattr(self, 'gauges', []) or [] + gauges = getattr(self, "gauges", []) or [] num_gauge_pairs_total = len(gauges) + def _is_drop_g(lab: str | None) -> bool: - return bool(lab) and ("_drop_" in lab or lab.startswith("QgX_drop_") or lab.startswith("QgZ_drop_")) + return bool(lab) and ( + "_drop_" in lab or lab.startswith(("QgX_drop_", "QgZ_drop_")) + ) + num_drop_gauge_pairs = 0 for pair in gauges: try: zg, xg = pair except Exception: zg, xg = None, None - if (zg is not None and _is_drop_g(getattr(zg, 'label', None))) or (xg is not None and _is_drop_g(getattr(xg, 'label', None))): + if (zg is not None and _is_drop_g(getattr(zg, "label", None))) or ( + xg is not None and _is_drop_g(getattr(xg, "label", None)) + ): num_drop_gauge_pairs += 1 # Quasis that changed support vs parent stabiliser (ignore one-hot DropX/DropZ) num_quasi_changed_supports = 0 for q in self.all_quasis: - lab = getattr(q, 'label', '') or '' - if lab.startswith('DropX(') or lab.startswith('DropZ('): + lab = getattr(q, "label", "") or "" + if lab.startswith(("DropX(", "DropZ(")): continue try: - parent_supp = set(int(x) for x in q.parent.qubit_map) # type: ignore[attr-defined] + parent_supp = {int(x) for x in q.parent.qubit_map} # type: ignore[attr-defined] except Exception: parent_supp = set() - if set(int(x) for x in q.support) != parent_supp: + if {int(x) for x in q.support} != parent_supp: num_quasi_changed_supports += 1 return { "num_quasi": len(self.all_quasis), @@ -748,7 +916,7 @@ def _is_drop_g(lab: str | None) -> bool: } # Convenience helpers for downstream tools (read-only) - def quasi_support(self, label: str) -> Tuple[str, List[int]]: + def quasi_support(self, label: str) -> tuple[str, list[int]]: """ Return (pauli_type, sorted list of code-qubit ids) for a quasi or stabiliser label. @@ -758,16 +926,16 @@ def quasi_support(self, label: str) -> Tuple[str, List[int]]: q = self.label_to_quasi.get(label) if q is None: # allow falling back to original stabiliser labels (untouched) - for stab in self.base_code.stabilisers.values(): + for stab in getattr(self.base_code, "stabilisers", {}).values(): if stab.label == label: return (stab.pauli_type, sorted(stab.qubit_map)) raise KeyError(f"Unknown quasi label: {label}") - return (q.pauli_type, sorted(list(q.support))) + return (q.pauli_type, sorted(q.support)) def anticommutation_graph(self) -> nx.Graph: return self.anticomm_graph.copy() - def products_list(self) -> List[QuasiProduct]: + def products_list(self) -> list[QuasiProduct]: return list(self.products) def prepare_solver(self, *, prune_params: dict | None = None) -> None: @@ -799,15 +967,21 @@ def schedule(self, L: int, solve_time: float = 60.0) -> SyndromeExtractionCircui """ if self.solver is None: self.prepare_solver() + assert self.solver is not None try: - layers = self.solver.create_layers_with_products(num_layers=L, solve_time=solve_time) - return SyndromeExtractionCircuit(layers=layers, solve_time=solve_time, L=L, dcode=self) + layers = self.solver.create_layers_with_products( + num_layers=L, solve_time=solve_time + ) + return SyndromeExtractionCircuit( + layers=layers, solve_time=solve_time, L=L, dcode=self + ) except Exception as e: from acid.solver.schedule_solver import ( SchedulingInfeasibleError, - SchedulingTimeLimitError, SchedulingModelInvalidError, + SchedulingTimeLimitError, ) + if isinstance(e, SchedulingInfeasibleError): raise ValueError( f"Scheduling infeasible at L={L} with product constraints. " @@ -822,72 +996,108 @@ def schedule(self, L: int, solve_time: float = 60.0) -> SyndromeExtractionCircui raise ValueError(f"Scheduling model invalid.\n{e}") raise - def visualisation_stim(self, embedding: Embedding, *, colour_map: Dict[str, str] | None = None, include_reset: bool = False, debug: bool = False) -> str: + def visualisation_stim( + self, + embedding: Embedding, + *, + colour_map: dict[str, str] | None = None, + include_reset: bool = False, + debug: bool = False, + ) -> str: """Return a .stim overlay for the device with polygons for quasis/products/gauges. include_reset: if True, include an initial TICK and a full-qubit R line. """ # Build connections list, prefer labelled classes if available from base_code - conns: List[Tuple[int, int, str]] = [] - bad_conns: Set[Tuple[int, int, str]] = set() - if getattr(self.base_code, 'connection_classes', None): + conns: list[tuple[int, int, str]] = [] + bad_conns: set[tuple[int, int, str]] = set() + if getattr(self.base_code, "connection_classes", None): # Use provided classes - for (u, v, cls) in (self.base_code.connection_classes or []): + for u, v, cls in self.base_code.connection_classes or []: conns.append((int(u), int(v), str(cls))) # Mark defective edges across all classes sharing the same undirected pair - dropped_norm = {(min(int(u), int(v)), max(int(u), int(v))) for (u, v) in self.dropped_edges} - for (u, v, cls) in (self.base_code.connection_classes or []): + dropped_norm = { + (min(int(u), int(v)), max(int(u), int(v))) + for (u, v) in self.dropped_edges + } + for u, v, cls in self.base_code.connection_classes or []: a, b = (int(u), int(v)) if int(u) <= int(v) else (int(v), int(u)) if (a, b) in dropped_norm: bad_conns.add((a, b, str(cls))) # Default colour map per class if not provided if colour_map is None: # Assign a few distinct colours; fall back to a default palette - palette = ["#4361ee", "#2a9d8f", "#e76f51", "#f4a261", "#e9c46a", "#8a5cff"] + palette = [ + "#4361ee", + "#2a9d8f", + "#e76f51", + "#f4a261", + "#e9c46a", + "#8a5cff", + ] classes = sorted({cls for _, _, cls in conns}) - colours = {cls: palette[i % len(palette)] for i, cls in enumerate(classes)} + colours = { + cls: palette[i % len(palette)] for i, cls in enumerate(classes) + } else: colours = colour_map else: # Fallback: single class 'E' for u, v in self.connectivity_graph.edges(): - conns.append((int(u), int(v), 'E')) - dropped_norm = {(min(int(u), int(v)), max(int(u), int(v))) for (u, v) in self.dropped_edges} - for (u, v) in dropped_norm: - bad_conns.add((u, v, 'E')) - colours = colour_map if colour_map is not None else {'E': '#4361ee'} + conns.append((int(u), int(v), "E")) + dropped_norm = { + (min(int(u), int(v)), max(int(u), int(v))) + for (u, v) in self.dropped_edges + } + for u, v in dropped_norm: + bad_conns.add((u, v, "E")) + colours = colour_map if colour_map is not None else {"E": "#4361ee"} if debug: - print("[viz] qubits=", self.base_code.num_qubits, "dropped_nodes=", len(self.dropped_nodes), "dropped_edges=", len(self.dropped_edges)) + print( + "[viz] qubits=", + self.base_code.num_qubits, + "dropped_nodes=", + len(self.dropped_nodes), + "dropped_edges=", + len(self.dropped_edges), + ) # Untouched stabilisers correspond to isolated quasis; use their post-dropout supports. if debug: print("[viz] base_code stabilisers:", len(list(self.base_code.shapes))) - label_to_quasi: Dict[str, QuasiStabiliser] = {q.label: q for q in self.all_quasis} - untouched: List[Tuple[str, List[int]]] = [] + label_to_quasi: dict[str, QuasiStabiliser] = { + q.label: q for q in self.all_quasis + } + untouched: list[tuple[str, Iterable[int]]] = [] for label in self.quasi_labels: if label in self.nontrivial_idx: continue q = label_to_quasi.get(label) if q is None: continue - untouched.append((q.pauli_type, sorted(list(q.support)))) + untouched.append((q.pauli_type, sorted(q.support))) if debug: print("[viz] untouched stabilisers:", len(untouched)) # Anticommuting quasi-stabilisers (nodes in anticomm graph) # Map label -> quasi info - anticomm_items: List[Tuple[str, List[int]]] = [] - for q in nx.get_node_attributes(self.anticomm_graph, 'quasi').values(): + anticomm_items: list[tuple[str, Iterable[int]]] = [] + for q in nx.get_node_attributes(self.anticomm_graph, "quasi").values(): anticomm_items.append((q.pauli_type, sorted(q.support))) if debug: - print("[viz] anticomm quasis (nodes):", len(list(self.anticomm_graph.nodes())), "rendered:", len(anticomm_items)) + print( + "[viz] anticomm quasis (nodes):", + len(list(self.anticomm_graph.nodes())), + "rendered:", + len(anticomm_items), + ) # Product stabilisers: XOR supports of member quasis - product_items: List[Tuple[str, List[int]]] = [] + product_items: list[tuple[str, Iterable[int]]] = [] if debug: print("[viz] product specs:", len(self.products)) for ps in self.products: - acc: Set[int] = set() + acc: set[int] = set() for m in ps.members: q = label_to_quasi.get(m) if q is None: @@ -899,29 +1109,31 @@ def visualisation_stim(self, embedding: Embedding, *, colour_map: Dict[str, str] print("[viz] product polygons:", len(product_items)) # Gauge items: combinations for the first r rows/cols in the diagonalization - gauge_items: List[Tuple[str, List[int]]] = [] + gauge_items: list[tuple[str, Iterable[int]]] = [] if debug: print("[viz] gauge rank:", self.r) + # helper to xor supports of member labels - def xor_supports(members: List[QuasiStabiliser]) -> List[int]: - acc: Set[int] = set() + def xor_supports(members: list[QuasiStabiliser]) -> list[int]: + acc: set[int] = set() for q in members: s = set(q.support) acc = (acc - s) | (s - acc) # symmetric difference return sorted(acc) + # Z gauge for i in range(min(self.r, len(self.U))): members = [self.z_anti_qs[k] for k, bit in enumerate(self.U[i]) if bit & 1] supp = xor_supports(members) if supp: - gauge_items.append(('Z', supp)) + gauge_items.append(("Z", supp)) # X gauge for i in range(min(self.r, len(self.VT))): members = [self.x_anti_qs[k] for k, bit in enumerate(self.VT[i]) if bit & 1] supp = xor_supports(members) if supp: - gauge_items.append(('X', supp)) + gauge_items.append(("X", supp)) if debug: print("[viz] gauge polygons:", len(gauge_items)) @@ -943,22 +1155,34 @@ def xor_supports(members: List[QuasiStabiliser]) -> List[int]: lines = stim.rstrip().splitlines() try: from acid.embedding import SquareGridEmbedding + is_torus = isinstance(embedding, SquareGridEmbedding) except Exception: is_torus = False if not is_torus: for i, ln in enumerate(lines): if ln.startswith("##! EMBEDDING TYPE=TORUS "): - lines[i] = f"##! EMBEDDING TYPE=PLANE LX={embedding.width} LY={embedding.height}" + lines[i] = ( + f"##! EMBEDDING TYPE=PLANE LX={embedding.width} LY={embedding.height}" + ) break return "\n".join(lines) + "\n" - def write_visualisation(self, out_path, embedding: Embedding, *, colour_map: Dict[str, str] | None = None, include_reset: bool = True) -> None: + def write_visualisation( + self, + out_path, + embedding: Embedding, + *, + colour_map: dict[str, str] | None = None, + include_reset: bool = True, + ) -> None: """ Write a .stim visualisation of the current code highlighting dropped qubits and edges (wrapper over visualisation_stim). """ - text = self.visualisation_stim(embedding, colour_map=colour_map, include_reset=include_reset) + text = self.visualisation_stim( + embedding, colour_map=colour_map, include_reset=include_reset + ) out_path = Path(out_path) out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text(text) diff --git a/ACID/src/acid/defects/quasi.py b/ACID/src/acid/defects/quasi.py index 09a3bc5..6d3b25d 100644 --- a/ACID/src/acid/defects/quasi.py +++ b/ACID/src/acid/defects/quasi.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import List @dataclass(frozen=True) @@ -7,12 +6,26 @@ class QuasiProduct: label: str pauli_type: str # Members are labels of quasi-stabilisers (strings) - members: List[str] + members: list[str] + @dataclass(frozen=True) class QuasiStabiliser: - pauli_type: str # 'X' or 'Z' - support: frozenset[int] # code-qubit ids - parent: object # original stabiliser (or shape) carrying label/graph/map - component_index: int # 0,1,2,... within parent stabiliser + """ + Represents a quasi-stabiliser, which is a stabiliser that may have been modified. + + Args: + pauli_type (str): The type of Pauli operator ('X' or 'Z'). + support (frozenset[int]): The set of code-qubit ids that this quasi-stabiliser acts on. + parent (object): The original stabiliser (or shape) that this quasi-stabiliser is + derived from, carrying label/graph/map information. + component_index (int): The index of this quasi-stabiliser within its + parent stabiliser (0, 1, 2, ...). + label (str): A unique label for this quasi-stabiliser. + """ + + pauli_type: str # 'X' or 'Z' + support: frozenset[int] # code-qubit ids + parent: object # original stabiliser (or shape) carrying label/graph/map + component_index: int # 0,1,2,... within parent stabiliser label: str diff --git a/ACID/src/acid/defects/syndrome_extraction_circuit.py b/ACID/src/acid/defects/syndrome_extraction_circuit.py index 8fadea4..0e175f7 100644 --- a/ACID/src/acid/defects/syndrome_extraction_circuit.py +++ b/ACID/src/acid/defects/syndrome_extraction_circuit.py @@ -1,46 +1,44 @@ from __future__ import annotations from typing import TYPE_CHECKING + if TYPE_CHECKING: from acid.defects.defective_code import DefectiveCode -from acid.pauli import AntiCommutingPauliBasis, CommutingPauliBasis, PauliString -from acid.scheduling.types import SyndromeExtractionLayer - - -from dataclasses import dataclass -from typing import Dict, List, Tuple, Any - import json +from dataclasses import dataclass +from typing import Any from acid.analysis.schedule import analyze_layers +from acid.pauli import AntiCommutingPauliBasis, CommutingPauliBasis, PauliString +from acid.scheduling.types import SyndromeExtractionLayer @dataclass class SyndromeExtractionCircuit: - layers: List[SyndromeExtractionLayer] + layers: list[SyndromeExtractionLayer] solve_time: float L: int - dcode: "DefectiveCode" + dcode: DefectiveCode def to_memory_stim(self, cycles: int) -> str: # Generalized schedule emitter for arbitrary number of layers if not self.layers: return "" - lines: List[str] = [] + lines: list[str] = [] n_qubits = self.dcode.base_code.num_qubits # Reset: RX on X-roots of layer 0, RZ everywhere else - # reuse helpers + # reuse helpers init_layer = self.layers[0] A_x_roots, _ = init_layer.roots_by_basis() rx_set = set(A_x_roots) rz_ids = [str(q) for q in range(n_qubits) if q not in rx_set] rx_ids = [str(q) for q in sorted(rx_set)] if rz_ids: - lines.append('RZ ' + ' '.join(rz_ids)) + lines.append("RZ " + " ".join(rz_ids)) if rx_ids: - lines.append('RX ' + ' '.join(rx_ids)) - lines.append('TICK') + lines.append("RX " + " ".join(rx_ids)) + lines.append("TICK") # Initial expand of layer 0 lines.extend(init_layer.emit_layer_expand()) @@ -53,19 +51,19 @@ def to_memory_stim(self, cycles: int) -> str: lines.extend(Lk.emit_layer_contract()) Lk_x_roots, Lk_z_roots = Lk.roots_by_basis() if Lk_x_roots: - lines.append('MX ' + ' '.join(str(q) for q in Lk_x_roots)) + lines.append("MX " + " ".join(str(q) for q in Lk_x_roots)) if Lk_z_roots: - lines.append('MZ ' + ' '.join(str(q) for q in Lk_z_roots)) - lines.append('TICK') + lines.append("MZ " + " ".join(str(q) for q in Lk_z_roots)) + lines.append("TICK") lines.extend(Lk.emit_layer_expand()) # Final contract of layer 0 and measure all Z lines.extend(init_layer.emit_layer_contract()) - lines.append('MZ ' + ' '.join(str(q) for q in range(n_qubits))) - return '\n'.join(lines) + '\n' + lines.append("MZ " + " ".join(str(q) for q in range(n_qubits))) + return "\n".join(lines) + "\n" # --- Serialization / Deserialization --- - def to_layers_dict(self) -> Dict[str, Any]: + def to_layers_dict(self) -> dict[str, Any]: """Serialize the circuit to a layers snapshot compatible with paper_data. Structure matches paper_data/bin/run_unit.py's ad hoc writer, so it can @@ -81,28 +79,37 @@ def to_layers_dict(self) -> Dict[str, Any]: analysis = analyze_layers(prod_members, self.layers, interesting_labels=None) all_labels = list(getattr(self.dcode, "quasi_labels", [])) # type: ignore[attr-defined] - out_layers: List[Dict[str, Any]] = [] + out_layers: list[dict[str, Any]] = [] for t, Lk in enumerate(self.layers): chosen_ids = {stab.label: int(shed.id) for stab, shed in Lk.chosen.items()} - full_map = {lab: (chosen_ids.get(lab) if lab in chosen_ids else None) for lab in all_labels} + full_map = { + lab: (chosen_ids.get(lab) if lab in chosen_ids else None) + for lab in all_labels + } measured_labels = sorted(chosen_ids.keys()) - per_t = analysis['per_layer'][t] if t < len(analysis.get('per_layer', [])) else {"in_process": [], "completed": []} - out_layers.append({ - "t": int(t), - "schedule_id_by_label": full_map, - "measured_labels": measured_labels, - "products": { - "in_process": list(per_t.get("in_process", [])), - "completed": list(per_t.get("completed", [])), - }, - }) + per_t = ( + analysis["per_layer"][t] + if t < len(analysis.get("per_layer", [])) + else {"in_process": [], "completed": []} + ) + out_layers.append( + { + "t": int(t), + "schedule_id_by_label": full_map, + "measured_labels": measured_labels, + "products": { + "in_process": list(per_t.get("in_process", [])), + "completed": list(per_t.get("completed", [])), + }, + } + ) return { "L": int(self.L), - "solve_time_ms": int(round(max(0.0, float(self.solve_time)) * 1000)), + "solve_time_ms": round(max(0.0, float(self.solve_time)) * 1000), "labels": all_labels, "layers": out_layers, - "product_completions": analysis.get('product_completions', {}), + "product_completions": analysis.get("product_completions", {}), } def to_layers_json(self, path: str | None = None) -> str: @@ -113,20 +120,20 @@ def to_layers_json(self, path: str | None = None) -> str: payload = self.to_layers_dict() s = json.dumps(payload, indent=2) if path is not None: - with open(path, 'w') as f: + with open(path, "w") as f: f.write(s) return s @classmethod def from_layers_dict( cls, - snapshot: Dict[str, Any], - dcode: "DefectiveCode", + snapshot: dict[str, Any], + dcode: DefectiveCode, *, verify: bool = True, strict: bool = True, backend: str = "solver", - ) -> "SyndromeExtractionCircuit": + ) -> SyndromeExtractionCircuit: """Rebuild a circuit from a layers snapshot. - verify=True: checks layer compatibility against a freshly computed @@ -137,7 +144,7 @@ def from_layers_dict( the layer.code; 'light' builds a minimal stub object with the required attributes for downstream end-cycle routines. """ - from acid.scheduling.types import StabiliserTemplate, Stabiliser + from acid.scheduling.types import Stabiliser, StabiliserTemplate from acid.solver.schedule_solver import ScheduleSolver L_val = int(snapshot.get("L", 0)) @@ -150,19 +157,21 @@ def from_layers_dict( set_in = set(labels_in) set_dc = set(d_labels) if strict and set_in != set_dc: - missing = sorted(list(set_dc - set_in)) - extra = sorted(list(set_in - set_dc)) + missing = sorted(set_dc - set_in) + extra = sorted(set_in - set_dc) raise ValueError( f"Label set mismatch between snapshot and defective code.\n" f"Missing: {missing}\n" f"Extra: {extra}" ) # Use intersection if not strict - valid_labels = sorted(list(set_in & set_dc)) if not strict else labels_in + valid_labels = sorted(set_in & set_dc) if not strict else labels_in # Build stabilisers map by label without solving - triplets: List[Tuple[StabiliserTemplate, List[int], str]] = getattr(dcode, "triplets", []) # type: ignore[attr-defined] - stab_by_label: Dict[str, Stabiliser] = {} + triplets: list[tuple[StabiliserTemplate, list[int], str]] = getattr( + dcode, "triplets", [] + ) # type: ignore[attr-defined] + stab_by_label: dict[str, Stabiliser] = {} for tmpl, qmap, lab in triplets: stab_by_label[lab] = tmpl.make_stabiliser(qmap, lab) @@ -172,22 +181,26 @@ def from_layers_dict( dcode.connectivity_graph, # type: ignore[attr-defined] triplets, anticommutation_graph=getattr(dcode, "anticomm_graph", None), # type: ignore[attr-defined] - product_stabilisers=getattr(dcode, "products", getattr(dcode, "products_list", lambda: [])()), # type: ignore[attr-defined] + product_stabilisers=getattr( + dcode, "products", getattr(dcode, "products_list", list)() + ), # type: ignore[attr-defined] ) code_for_layer = solver else: # Minimal stub providing .stabilisers and .num_qubits class _StubCode: - def __init__(self, stab_map: Dict[str, Stabiliser], n: int): + def __init__(self, stab_map: dict[str, Stabiliser], n: int): self.stabilisers = stab_map self.num_qubits = int(n) - code_for_layer = _StubCode(stab_by_label, getattr(dcode.base_code, "num_qubits", 0)) # type: ignore[attr-defined] + code_for_layer = _StubCode( + stab_by_label, getattr(dcode.base_code, "num_qubits", 0) + ) # type: ignore[attr-defined] - layers_out: List[SyndromeExtractionLayer] = [] + layers_out: list[SyndromeExtractionLayer] = [] for ent in layers_in: sched_map = ent.get("schedule_id_by_label", {}) - chosen: Dict[Stabiliser, Any] = {} + chosen: dict[Stabiliser, Any] = {} for lab in valid_labels: sid = sched_map.get(lab, None) if sid is None: @@ -198,36 +211,51 @@ def __init__(self, stab_map: Dict[str, Stabiliser], n: int): sid_int = int(sid) sheds = stab.stabiliser_template.schedules if not (0 <= sid_int < len(sheds)): - raise ValueError(f"Invalid schedule id {sid_int} for label {lab}; K={len(sheds)}") + raise ValueError( + f"Invalid schedule id {sid_int} for label {lab}; K={len(sheds)}" + ) chosen[stab] = sheds[sid_int] Lk = SyndromeExtractionLayer(chosen=chosen, code=code_for_layer) if verify and hasattr(code_for_layer, "scheduling_graph"): - if not Lk.is_compatible_with_scheduling_graph(code_for_layer.scheduling_graph): # type: ignore[attr-defined] - raise ValueError("Layer not compatible with scheduling graph (verification failed)") + if not Lk.is_compatible_with_scheduling_graph( + code_for_layer.scheduling_graph + ): # type: ignore[attr-defined] + raise ValueError( + "Layer not compatible with scheduling graph (verification failed)" + ) layers_out.append(Lk) if len(layers_out) != L_val: # Not fatal, but warn via exception to enforce consistency - raise ValueError(f"Snapshot L={L_val} but constructed {len(layers_out)} layers") + raise ValueError( + f"Snapshot L={L_val} but constructed {len(layers_out)} layers" + ) - return SyndromeExtractionCircuit(layers=layers_out, solve_time=float(solve_time_ms) / 1000.0, L=L_val, dcode=dcode) + return SyndromeExtractionCircuit( + layers=layers_out, + solve_time=float(solve_time_ms) / 1000.0, + L=L_val, + dcode=dcode, + ) @classmethod def from_layers_json( cls, path: str, - dcode: "DefectiveCode", + dcode: DefectiveCode, *, verify: bool = True, strict: bool = True, backend: str = "solver", - ) -> "SyndromeExtractionCircuit": - with open(path, 'r') as f: + ) -> SyndromeExtractionCircuit: + with open(path, "r") as f: snapshot = json.load(f) - return cls.from_layers_dict(snapshot, dcode, verify=verify, strict=strict, backend=backend) + return cls.from_layers_dict( + snapshot, dcode, verify=verify, strict=strict, backend=backend + ) - def commuting_bases(self) -> List[CommutingPauliBasis]: - bases: List[CommutingPauliBasis] = [] + def commuting_bases(self) -> list[CommutingPauliBasis]: + bases: list[CommutingPauliBasis] = [] bases.append(self.dcode.midcycle_untouched_stabilisers()) prod = self.dcode.midcycle_product_stabilisers() if prod is not None: @@ -236,28 +264,40 @@ def commuting_bases(self) -> List[CommutingPauliBasis]: # but we can use existing endcycle_expanded_stabilisers to construct supports. for idx, Lk in enumerate(self.layers): x_rows, z_rows, _ = Lk.endcycle_expanded_stabilisers() - basis = CommutingPauliBasis.from_supports(name=f"EndCycle[{idx}]", priority=2+idx, x_supports=x_rows, z_supports=z_rows, n=self.dcode.base_code.num_qubits) + basis = CommutingPauliBasis.from_supports( + name=f"EndCycle[{idx}]", + priority=2 + idx, + x_supports=x_rows, + z_supports=z_rows, + n=self.dcode.base_code.num_qubits, + ) bases.append(basis) # Sort by priority (higher first) bases.sort(key=lambda b: b.priority, reverse=True) return bases - def anticommuting_bases(self) -> Dict[str, AntiCommutingPauliBasis]: - bases: Dict[str, AntiCommutingPauliBasis] = {} + def anticommuting_bases(self) -> dict[str, AntiCommutingPauliBasis]: + bases: dict[str, AntiCommutingPauliBasis] = {} Lx_mid, Lz_mid = self.dcode._logical_pairs_mid_paulis() Gx_mid, Gz_mid = self.dcode._gauge_pairs_mid_paulis() - bases["Lmid"] = AntiCommutingPauliBasis(name="Lmid", X_rows=Lx_mid, Z_rows=Lz_mid) - bases["Gmid"] = AntiCommutingPauliBasis(name="Gmid", X_rows=Gx_mid, Z_rows=Gz_mid) + bases["Lmid"] = AntiCommutingPauliBasis( + name="Lmid", X_rows=Lx_mid, Z_rows=Lz_mid + ) + bases["Gmid"] = AntiCommutingPauliBasis( + name="Gmid", X_rows=Gx_mid, Z_rows=Gz_mid + ) # Per-layer propagated logicals for idx, Lk in enumerate(self.layers): - Xp: List[PauliString] = [] - Zp: List[PauliString] = [] + Xp: list[PauliString] = [] + Zp: list[PauliString] = [] for p in Lx_mid: Xp.append(Lk.propagate(p)) for p in Lz_mid: Zp.append(Lk.propagate(p)) - bases[f"L{idx}"] = AntiCommutingPauliBasis(name=f"L{idx}", X_rows=Xp, Z_rows=Zp) + bases[f"L{idx}"] = AntiCommutingPauliBasis( + name=f"L{idx}", X_rows=Xp, Z_rows=Zp + ) # Per-layer gauges (if any) # for idx, Lk in enumerate(self.layers): @@ -271,5 +311,4 @@ def anticommuting_bases(self) -> Dict[str, AntiCommutingPauliBasis]: # Zp.append(Lk.propagate(p)) # bases[f"G{idx}"] = AntiCommutingPauliBasis(name=f"G{idx}", X_rows=Xp, Z_rows=Zp) - return bases diff --git a/ACID/src/acid/device.py b/ACID/src/acid/device.py index 7cad199..b6f0806 100644 --- a/ACID/src/acid/device.py +++ b/ACID/src/acid/device.py @@ -1,48 +1,52 @@ from __future__ import annotations + """Overlay emitter for device geometry and schedule‑context polygons. Produces a Stim text prefix with qubit coords, connection sheets per class, and optional polygons for untouched/anticommuting/product/gauge regions. """ -from dataclasses import dataclass -from typing import Iterable, List, Set, Tuple, Dict, DefaultDict -from collections import defaultdict import math +from collections.abc import Iterable +from dataclasses import dataclass -from .codes.bb.algebra import GroupRing, Monomial, Polynomial from .embedding import Embedding @dataclass(frozen=True) class Connection: - a: Tuple[int, int, int] - b: Tuple[int, int, int] + a: tuple[int, int, int] + b: tuple[int, int, int] z: int = 0 defective: bool = False - def key(self) -> Tuple[Tuple[int, int, int], Tuple[int, int, int]]: + def key(self) -> tuple[tuple[int, int, int], tuple[int, int, int]]: return tuple(sorted((self.a, self.b))) # undirected @dataclass class DeviceVisualisation: n_qubits: int - embedding: Embedding # provides qubit_id, coords, id_to_tuple - qubit_colouring: dict[int, str] # qubit_id -> colour - connections: List[Tuple[int, int, str]] # qubit_1, qubit_2, connection_class - defective_qubits: Set[int] # qubit_ids. mark these qubits as defective in the .stim file - defective_connections: Set[Tuple[int, int, str]] # (qubit_1, qubit_2, connection_class). mark as defective in the .stim file - connection_class_colours: Dict[str, str] # connection_class -> colour + embedding: Embedding # provides qubit_id, coords, id_to_tuple + qubit_colouring: dict[int, str] # qubit_id -> colour + connections: list[tuple[int, int, str]] # qubit_1, qubit_2, connection_class + defective_qubits: set[ + int + ] # qubit_ids. mark these qubits as defective in the .stim file + defective_connections: set[ + tuple[int, int, str] + ] # (qubit_1, qubit_2, connection_class). mark as defective in the .stim file + connection_class_colours: dict[str, str] # connection_class -> colour # Optional polygon overlays per category: list of ('X'|'Z', [qubit_ids...]) - polygons_untouched: List[Tuple[str, Iterable[int]]] = None - polygons_anticomm: List[Tuple[str, Iterable[int]]] = None - polygons_products: List[Tuple[str, Iterable[int]]] = None - polygons_gauge: List[Tuple[str, Iterable[int]]] = None - - - def stim_with_overlays(self, include_reset: bool = True, *, debug: bool = False) -> str: - lines: List[str] = [] + polygons_untouched: list[tuple[str, Iterable[int]]] | None = None + polygons_anticomm: list[tuple[str, Iterable[int]]] | None = None + polygons_products: list[tuple[str, Iterable[int]]] | None = None + polygons_gauge: list[tuple[str, Iterable[int]]] | None = None + + def stim_with_overlays( + self, include_reset: bool = True, *, debug: bool = False + ) -> str: + lines: list[str] = [] # Dynamic legend/comment header lines.append("# Legend") lines.append("# Qubits: L (c=0) = gold, R (c=1) = mediumseagreen") @@ -51,18 +55,24 @@ def stim_with_overlays(self, include_reset: bool = True, *, debug: bool = False) lines.append(f"# - {name}: {colour}") # Prepare polygon categories first so all SHEET statements can appear at top - cats: List[Tuple[str, List[Tuple[str, Iterable[int]]]]] = [ - ("UNTX", []), ("UNTZ", []), - ("ANTIX", []), ("ANTIZ", []), - ("PRODX", []), ("PRODZ", []), - ("GAUGEX", []), ("GAUGEZ", []), + cats: list[tuple[str, list[tuple[str, Iterable[int]]]]] = [ + ("UNTX", []), + ("UNTZ", []), + ("ANTIX", []), + ("ANTIZ", []), + ("PRODX", []), + ("PRODZ", []), + ("GAUGEX", []), + ("GAUGEZ", []), ] - def assign_items(items: List[Tuple[str, Iterable[int]]], x_name: str, z_name: str): + def assign_items( + items: list[tuple[str, Iterable[int]]], x_name: str, z_name: str + ): if not items: return for ptype, verts in items: - if ptype and ptype.upper() == 'X': + if ptype and ptype.upper() == "X": for idx, (nm, arr) in enumerate(cats): if nm == x_name: arr.append(tuple(int(q) for q in verts)) @@ -81,9 +91,11 @@ def assign_items(items: List[Tuple[str, Iterable[int]]], x_name: str, z_name: st assign_items(self.polygons_gauge or [], "GAUGEX", "GAUGEZ") # Embedding declaration (torus) - lines.append(f"##! EMBEDDING TYPE=TORUS LX={self.embedding.width} LY={self.embedding.height}") + lines.append( + f"##! EMBEDDING TYPE=TORUS LX={self.embedding.width} LY={self.embedding.height}" + ) # Build sheet layout: QUBITS (0), connection class sheets (1..C), then polygon sheets - sheet_defs: List[Tuple[str, int]] = [("QUBITS", 0)] + sheet_defs: list[tuple[str, int]] = [("QUBITS", 0)] base = 1 for i, name in enumerate(self.connection_class_colours.keys()): sheet_defs.append((name, base + i)) @@ -103,7 +115,9 @@ def assign_items(items: List[Tuple[str, Iterable[int]]], x_name: str, z_name: st q_tuple = self.embedding.id_to_tuple(qid) coords = self.embedding.coords(*q_tuple) c = q_tuple[2] if len(q_tuple) > 2 else 0 - q_colour = self.qubit_colouring.get(qid, "gold" if c == 0 else "mediumseagreen") + q_colour = self.qubit_colouring.get( + qid, "gold" if c == 0 else "mediumseagreen" + ) attrs = [ f"Q={qid}", "SHEET=QUBITS", @@ -118,20 +132,29 @@ def assign_items(items: List[Tuple[str, Iterable[int]]], x_name: str, z_name: st lines.append(f"QUBIT_COORDS({coords[0]:.6g}, {coords[1]:.6g}) {qid}") # Prepare optional initial tick/reset; appended after overlays if enabled - tick_reset: List[str] = [] + tick_reset: list[str] = [] if include_reset: tick_reset.append("TICK") all_ids = [str(qid) for qid in range(self.n_qubits)] if all_ids: tick_reset.append("R " + " ".join(all_ids)) - def emit_conn_set(sheet: str, conns: List[Tuple[int, int, str]], colour: str | None = None, defective: bool = False): + def emit_conn_set( + sheet: str, + conns: list[tuple[int, int, str]], + colour: str | None = None, + defective: bool = False, + ): edges = [f"{a}-{b}" for a, b, cls in conns if cls == sheet] if edges: # For defective connections, simply force colour red without extra flags. local_colour = "red" if defective else colour # Add explicit thickness for edges (Shatter directive) - base = f"##! CONN SET SHEET={sheet} EDGES=(" + ",".join(edges) + ") THICKNESS=2" + base = ( + f"##! CONN SET SHEET={sheet} EDGES=(" + + ",".join(edges) + + ") THICKNESS=2" + ) if local_colour: base += f" COLOUR={local_colour}" lines.append(base) @@ -139,7 +162,11 @@ def emit_conn_set(sheet: str, conns: List[Tuple[int, int, str]], colour: str | N # Emit connections per class for name, colour in self.connection_class_colours.items(): # Good connections - good_conns = [conn for conn in self.connections if conn[2] == name and conn not in self.defective_connections] + good_conns = [ + conn + for conn in self.connections + if conn[2] == name and conn not in self.defective_connections + ] emit_conn_set(name, good_conns, colour, defective=False) # Defective connections bad_conns = [conn for conn in self.defective_connections if conn[2] == name] @@ -153,12 +180,18 @@ def emit_conn_set(sheet: str, conns: List[Tuple[int, int, str]], colour: str | N print(f"[viz] polygons sheet {nm}: count={len(polys)}") for verts in polys: ordered = self._order_polygon_clockwise(verts) - if 'X' in nm: + if "X" in nm: lines.append(f"##! POLY SHEET={nm}") - lines.append("#!pragma POLYGON(1,0,0,0.15) " + " ".join(str(q) for q in ordered)) + lines.append( + "#!pragma POLYGON(1,0,0,0.15) " + + " ".join(str(q) for q in ordered) + ) else: lines.append(f"##! POLY SHEET={nm}") - lines.append("#!pragma POLYGON(0,0,1,0.15) " + " ".join(str(q) for q in ordered)) + lines.append( + "#!pragma POLYGON(0,0,1,0.15) " + + " ".join(str(q) for q in ordered) + ) # Append the tick/reset after overlays, if requested lines.extend(tick_reset) @@ -169,14 +202,14 @@ def emit_conn_set(sheet: str, conns: List[Tuple[int, int, str]], colour: str | N lines.append(f"##! HIGHLIGHT TARGET=QUBIT QUBITS={q_list} COLOR=red") return "\n".join(lines) + "\n" - def _order_polygon_clockwise(self, qids: Iterable[int]) -> List[int]: + def _order_polygon_clockwise(self, qids: Iterable[int]) -> list[int]: """Return qubit ids ordered clockwise around their centroid. Uses the embedding's coordinates for geometry. If there are fewer than 3 unique vertices, returns the input order (deduplicated). """ - pts: List[Tuple[int, float, float]] = [] - seen: Set[int] = set() + pts: list[tuple[int, float, float]] = [] + seen: set[int] = set() for q in qids: qi = int(q) if qi in seen: @@ -189,8 +222,12 @@ def _order_polygon_clockwise(self, qids: Iterable[int]) -> List[int]: return [p[0] for p in pts] cx = sum(p[1] for p in pts) / len(pts) cy = sum(p[2] for p in pts) / len(pts) - def angle(p: Tuple[int, float, float]) -> float: + + def angle(p: tuple[int, float, float]) -> float: return math.atan2(p[2] - cy, p[1] - cx) + # Sort by angle descending for clockwise order; tie-break by radius - ordered = sorted(pts, key=lambda p: (-angle(p), (p[1]-cx)**2 + (p[2]-cy)**2)) + ordered = sorted( + pts, key=lambda p: (-angle(p), (p[1] - cx) ** 2 + (p[2] - cy) ** 2) + ) return [p[0] for p in ordered] diff --git a/ACID/src/acid/embedding.py b/ACID/src/acid/embedding.py index 4690194..45ae410 100644 --- a/ACID/src/acid/embedding.py +++ b/ACID/src/acid/embedding.py @@ -1,33 +1,32 @@ from __future__ import annotations + """Embedding abstractions for mapping code coordinates to planar layouts. - SquareGridEmbedding: periodic (torus) with L/R qubits per cell. - CoordMapEmbedding: explicit integer grid coordinates (planar). """ -from dataclasses import dataclass -from typing import Tuple, Dict from abc import ABC, abstractmethod +from dataclasses import dataclass from .codes.bb.algebra import GroupRing, Monomial class Embedding(ABC): - @abstractmethod def qubit_id(self, a: int, b: int, c: int) -> int: pass @abstractmethod - def id_to_tuple(self, qid: int) -> Tuple[int, int, int]: + def id_to_tuple(self, qid: int) -> tuple[int, int, int]: pass - + @abstractmethod - def coords(self, a: int, b: int, c: int) -> Tuple[float, float]: + def coords(self, a: int, b: int, c: int) -> tuple[float, float]: pass @abstractmethod - def id_and_coords_for(self, g: Monomial, c: int) -> Tuple[int, Tuple[float, float]]: + def id_and_coords_for(self, g: Monomial, c: int) -> tuple[int, tuple[float, float]]: pass @property @@ -43,6 +42,18 @@ def width(self) -> int: @dataclass class SquareGridEmbedding(Embedding): + """Periodic (torus) square-grid embedding for bivariate bicycle codes. + + Each cell (a, b) in Z_l x Z_m holds two qubits: a left qubit (c=0) and a + right qubit (c=1). Left qubits are offset half a pitch in x; right qubits + are offset half a pitch in y, producing a checkerboard-style layout. + + Attributes: + ring: The group ring Z_l x Z_m defining the code lattice. + pitch: Spacing between adjacent cells in the planar layout. + num_qubits: Total number of qubits (set automatically to l * m * 2). + """ + ring: GroupRing pitch: float = 1.0 num_qubits: int = 0 # will be set in __post_init__ @@ -53,44 +64,46 @@ def __post_init__(self): def qubit_id(self, a: int, b: int, c: int) -> int: a0, b0 = self.ring.canonical(a, b) return ((a0 * self.ring.m) + b0) * 2 + (c & 1) - - def id_to_tuple(self, qid: int) -> Tuple[int, int, int]: + + def id_to_tuple(self, qid: int) -> tuple[int, int, int]: assert 0 <= qid < self.num_qubits, "Qubit ID out of range" a = (qid // 2) // self.ring.m b = (qid // 2) % self.ring.m c = qid % 2 return (a, b, c) - def coords(self, a: int, b: int, c: int) -> Tuple[float, float]: + def coords(self, a: int, b: int, c: int) -> tuple[float, float]: a0, b0 = self.ring.canonical(a, b) p = self.pitch x = a0 * p + (c & 1) * (p / 2) y = b0 * p + (1 - (c & 1)) * (p / 2) return x, y - def id_and_coords_for(self, g: Monomial, c: int) -> Tuple[int, Tuple[float, float]]: + def id_and_coords_for(self, g: Monomial, c: int) -> tuple[int, tuple[float, float]]: i = self.qubit_id(g.a, g.b, c) return i, self.coords(g.a, g.b, c) - + @property def height(self) -> int: - return self.ring.m + return self.ring.m + @property def width(self) -> int: return self.ring.l + class CoordMapEmbedding(Embedding): - def __init__(self, xy_to_id: Dict[Tuple[int, int], int]): + def __init__(self, xy_to_id: dict[tuple[int, int], int]): self._xy_to_id = dict(xy_to_id) self._id_to_xy = {qid: xy for xy, qid in self._xy_to_id.items()} self.num_qubits = len(self._id_to_xy) - self._width = max(x for x, _ in self._xy_to_id.keys()) + 1 if self._xy_to_id else 0 - self._height = max(y for _, y in self._xy_to_id.keys()) + 1 if self._xy_to_id else 0 + self._width = max(x for x, _ in self._xy_to_id) + 1 if self._xy_to_id else 0 + self._height = max(y for _, y in self._xy_to_id) + 1 if self._xy_to_id else 0 def qubit_id(self, a: int, b: int, c: int) -> int: return self._xy_to_id[(a, b)] - def id_to_tuple(self, qid: int) -> Tuple[int, int, int]: + def id_to_tuple(self, qid: int) -> tuple[int, int, int]: x, y = self._id_to_xy[qid] return (x, y, 0) diff --git a/ACID/src/acid/gap_distance.py b/ACID/src/acid/gap_distance.py index 3343249..6b4c51c 100644 --- a/ACID/src/acid/gap_distance.py +++ b/ACID/src/acid/gap_distance.py @@ -1,9 +1,9 @@ from __future__ import annotations +import re import shutil import subprocess -from typing import List, Sequence, Tuple -import re +from collections.abc import Sequence def _validate_binary_matrix(M: Sequence[Sequence[int]]) -> None: @@ -36,7 +36,7 @@ def compute_nkd_with_gap( mindist: int = 0, debug: int = 1, timeout: int = 300, -) -> Tuple[int, int, int]: +) -> tuple[int, int, int]: """ Compute (n, k, d) using GAP + QDistRnd package. @@ -52,20 +52,30 @@ def compute_nkd_with_gap( _validate_binary_matrix(Hx) _validate_binary_matrix(Hz) - gap_lines: List[str] = [] + gap_lines: list[str] = [] gap_lines.append("F := GF(2);") - gap_lines.append('if not LoadPackage("QDistRnd") then Error("QDistRnd package not found"); fi;') + gap_lines.append( + 'if not LoadPackage("QDistRnd") then Error("QDistRnd package not found"); fi;' + ) gap_lines.append(f"Hx := {_gap_matrix_literal(Hx)};") gap_lines.append(f"Hz := {_gap_matrix_literal(Hz)};") # Robust column count even when one side is empty gap_lines.append("n := Maximum(NrCols(Hx), NrCols(Hz));") gap_lines.append("k := n - RankMat(Hx) - RankMat(Hz);") - gap_lines.append(f"d := DistRandCSS(Hz, Hx, {int(trials)}, {int(mindist)}, {int(debug)} : field := F);") + gap_lines.append( + f"d := DistRandCSS(Hz, Hx, {int(trials)}, {int(mindist)}, {int(debug)} : field := F);" + ) # Print with explicit sentinels to simplify parsing # Emit sentinels without embedding literal newlines inside a GAP string - gap_lines.append('Print("N=");'); gap_lines.append('Print(n);'); gap_lines.append('Print("\\n");') - gap_lines.append('Print("K=");'); gap_lines.append('Print(k);'); gap_lines.append('Print("\\n");') - gap_lines.append('Print("D=");'); gap_lines.append('Print(d);'); gap_lines.append('Print("\\n");') + gap_lines.append('Print("N=");') + gap_lines.append("Print(n);") + gap_lines.append('Print("\\n");') + gap_lines.append('Print("K=");') + gap_lines.append("Print(k);") + gap_lines.append('Print("\\n");') + gap_lines.append('Print("D=");') + gap_lines.append("Print(d);") + gap_lines.append('Print("\\n");') gap_lines.append("QUIT;") script = "\n".join(gap_lines) diff --git a/ACID/src/acid/gf2_utils.py b/ACID/src/acid/gf2_utils.py index aa2f1a7..94d14ba 100644 --- a/ACID/src/acid/gf2_utils.py +++ b/ACID/src/acid/gf2_utils.py @@ -1,10 +1,9 @@ from __future__ import annotations -from typing import List, Tuple import numpy as np -def gf2_rref_colwise(M: List[List[int]], clear_upper_triangle = True) -> List[List[int]]: +def gf2_rref_colwise(M: list[list[int]], clear_upper_triangle=True) -> list[list[int]]: """Return column-wise row-reduced echelon form over GF(2). Return pivot cols. M is a list of rows of equal length containing 0/1. @@ -14,7 +13,7 @@ def gf2_rref_colwise(M: List[List[int]], clear_upper_triangle = True) -> List[Li # Transpose M to get columns as rows m, n = len(M), len(M[0]) A = [row[:] for row in M] - pivots: List[int] = [] + pivots: list[int] = [] for r in range(m): # Find pivot in row r pivot_c = None @@ -37,11 +36,13 @@ def gf2_rref_colwise(M: List[List[int]], clear_upper_triangle = True) -> List[Li # assert gf2_rank(A[:r+1]) == gf2_rank(M[:r + 1]) == gf2_rank(A[:r+1] + M[:r + 1]) if r == m: break - + return A, pivots -def gf2_rref_rowwise(M: List[List[int]], clear_upper_triangle = True) -> Tuple[List[List[int]], List[int]]: +def gf2_rref_rowwise( + M: list[list[int]], clear_upper_triangle=True +) -> tuple[list[list[int]], list[int]]: """Return row-reduced echelon form over GF(2) and list of pivot columns. M is a list of rows of equal length containing 0/1. @@ -51,7 +52,7 @@ def gf2_rref_rowwise(M: List[List[int]], clear_upper_triangle = True) -> Tuple[L A = [row[:] for row in M] m = len(A) n = len(A[0]) - pivots: List[int] = [] + pivots: list[int] = [] r = 0 for c in range(n): # find pivot @@ -79,13 +80,14 @@ def gf2_rref_rowwise(M: List[List[int]], clear_upper_triangle = True) -> Tuple[L return A, pivots -def gf2_rank(M: List[List[int]]) -> int: +def gf2_rank(M: list[list[int]]) -> int: if not M: return 0 _, piv = gf2_rref_rowwise(M) return len(piv) -def gf2_nullspace(M: List[List[int]]) -> List[List[int]]: + +def gf2_nullspace(M: list[list[int]]) -> list[list[int]]: """Return a basis for the right nullspace of M over GF(2). Each vector x satisfies M x = 0 (treating rows of M and column vector x). @@ -98,7 +100,7 @@ def gf2_nullspace(M: List[List[int]]) -> List[List[int]]: n = len(R[0]) if m else 0 pivot_pos = set(piv) free_cols = [j for j in range(n) if j not in pivot_pos] - basis: List[List[int]] = [] + basis: list[list[int]] = [] # For each free variable, set it to 1 and solve for pivot vars for f in free_cols: x = [0] * n @@ -113,7 +115,8 @@ def gf2_nullspace(M: List[List[int]]) -> List[List[int]]: basis.append(x) return basis -def gf2_left_nullspace(M: List[List[int]]) -> List[List[int]]: + +def gf2_left_nullspace(M: list[list[int]]) -> list[list[int]]: """Return a basis for the left nullspace of M, i.e., vectors w with w M = 0. Compute nullspace of M^T. @@ -123,7 +126,7 @@ def gf2_left_nullspace(M: List[List[int]]) -> List[List[int]]: # Transpose M to get M^T (n x m) m = len(M) n = len(M[0]) if m else 0 - MT: List[List[int]] = [[0] * m for _ in range(n)] + MT: list[list[int]] = [[0] * m for _ in range(n)] for i in range(m): row = M[i] for j in range(n): @@ -132,7 +135,10 @@ def gf2_left_nullspace(M: List[List[int]]) -> List[List[int]]: # Right nullspace of M^T gives left nullspace of M return gf2_nullspace(MT) -def gf2_bidiagonalize(A: List[List[int]]) -> tuple[List[List[int]], List[List[int]], int]: + +def gf2_bidiagonalize( + A: list[list[int]], +) -> tuple[list[list[int]], list[list[int]], int]: """ Perform GF(2) row/column elimination to diagonalize A via U * A * V^T = diag(I_r, 0), returning (U, V, r). @@ -149,21 +155,27 @@ def gf2_bidiagonalize(A: List[List[int]]) -> tuple[List[List[int]], List[List[in i = j = 0 r = 0 while i < b and j < a: + # find first nonzero entry in submatrix M[i:b, j:a], this is the pivot pi = pj = None found = False for ii in range(i, b): for jj in range(j, a): if M[ii][jj] & 1: - pi, pj = ii, jj; found = True; break + pi, pj = ii, jj + found = True + break if found: break if not found: + # no more pivots; we're done break - # Swap to (i,j) + # swap found pibot into position (i, j) if pi != i: + # swap rows i and pi in M and U M[i], M[pi] = M[pi], M[i] U[i], U[pi] = U[pi], U[i] if pj != j: + # swap columns j and pj in M and V for rr in range(b): M[rr][j], M[rr][pj] = M[rr][pj], M[rr][j] for rr in range(a): @@ -182,11 +194,13 @@ def gf2_bidiagonalize(A: List[List[int]]) -> tuple[List[List[int]], List[List[in M[rr][jj] ^= M[rr][j] for rr in range(a): V[rr][jj] ^= V[rr][j] - i += 1; j += 1; r += 1 + i += 1 + j += 1 + r += 1 return U, V, r -def gf2_is_in_span(v: List[int], basis: List[List[int]]) -> bool: +def gf2_is_in_span(v: list[int], basis: list[list[int]]) -> bool: """Check if vector v is in the span of basis rows over GF(2).""" if not basis: return all(x == 0 for x in v) @@ -198,7 +212,8 @@ def gf2_is_in_span(v: List[int], basis: List[List[int]]) -> bool: rank_after = gf2_rank(basis + [v]) return rank_after == rank_before -def gf2_are_not_in_span(rows: List[List[int]], basis: List[List[int]]) -> bool: + +def gf2_are_not_in_span(rows: list[list[int]], basis: list[list[int]]) -> bool: """Check if matrix has null intersection with basis rows over GF(2).""" if not basis: return all(x == 0 for x in rows) @@ -212,17 +227,20 @@ def gf2_are_not_in_span(rows: List[List[int]], basis: List[List[int]]) -> bool: return rank_total == rank_basis + rank_rows -def gf2_rref_numpy(A_in): +def gf2_rank_normal_numpy( + A_in, +) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, int]: """ - Compute the reduced row echelon form of matrix A modulo 2 and track transformations. - Returns R_inv, C_inv and R, C such that A = R @ rref @ C and R_inv @ A @ C_inv = rref - + Compute the rank normal form of matrix A modulo 2 and track transformations. + Returns R_inv, C_inv and R, C such that A = R @ rank_normal @ C and R_inv @ A @ C_inv = rank_normal. + Very similar to gf2_bidiagonalize, but returns the rank normal form instead of just the rank. + Args: - A (np.ndarray): Input matrix with integer or boolean dtype - + A_in (np.ndarray): Input matrix with integer or boolean dtype + Returns: - tuple: (rref, R_inv, R, C_inv, C, rank) - rref (np.ndarray): Reduced row echelon form of A + tuple: (rank_normal, R_inv, R, C_inv, C, rank) + rank_normal (np.ndarray): Rank normal form of A R_inv (np.ndarray): Inverse row transformation matrix in GL(m,2) R (np.ndarray): Row transformation matrix in GL(m,2) C_inv (np.ndarray): Inverse column permutation matrix @@ -231,11 +249,11 @@ def gf2_rref_numpy(A_in): """ # Make a copy, and convert to int8 if not already - if A_in.dtype.kind not in 'bi': - raise ValueError('Input array must have integer dtype') + if A_in.dtype.kind not in "bi": + raise ValueError("Input array must have integer dtype") A = np.array(A_in, dtype=np.int8) m, n = A.shape - + # Initialize identity matrices for R and C R_inv = np.eye(m, dtype=np.int8) R = np.eye(m, dtype=np.int8) @@ -256,14 +274,14 @@ def gf2_rref_numpy(A_in): pivot_row = np.nonzero(A[rank_so_far:, pivot_column])[0][0] + rank_so_far # Permute pivot row into place - A[[pivot_row,rank_so_far]] = A[[rank_so_far,pivot_row]] - R_inv[[pivot_row,rank_so_far]] = R_inv[[rank_so_far,pivot_row]] - R[:,[pivot_row,rank_so_far]] = R[:,[rank_so_far,pivot_row]] + A[[pivot_row, rank_so_far]] = A[[rank_so_far, pivot_row]] + R_inv[[pivot_row, rank_so_far]] = R_inv[[rank_so_far, pivot_row]] + R[:, [pivot_row, rank_so_far]] = R[:, [rank_so_far, pivot_row]] # Permute pivot column into place - A[:,[pivot_column,rank_so_far]] = A[:,[rank_so_far,pivot_column]] - C_inv[:,[pivot_column,rank_so_far]] = C_inv[:,[rank_so_far,pivot_column]] - C[[pivot_column,rank_so_far]] = C[[rank_so_far,pivot_column]] + A[:, [pivot_column, rank_so_far]] = A[:, [rank_so_far, pivot_column]] + C_inv[:, [pivot_column, rank_so_far]] = C_inv[:, [rank_so_far, pivot_column]] + C[[pivot_column, rank_so_far]] = C[[rank_so_far, pivot_column]] # Find which rows need to be flipped (in-place pivoting workaround) A[rank_so_far, rank_so_far] = 0 @@ -274,5 +292,5 @@ def gf2_rref_numpy(A_in): # Flip the rows A[targets] ^= A[rank_so_far] R_inv[targets] ^= R_inv[rank_so_far] - R[:,rank_so_far] ^= (np.sum(R[:,targets], axis=1) % 2) + R[:, rank_so_far] ^= np.sum(R[:, targets], axis=1) % 2 rank_so_far += 1 diff --git a/ACID/src/acid/memory_experiment/__init__.py b/ACID/src/acid/memory_experiment/__init__.py index d97d4db..aaddf65 100644 --- a/ACID/src/acid/memory_experiment/__init__.py +++ b/ACID/src/acid/memory_experiment/__init__.py @@ -1,11 +1,10 @@ from .experiment import MemoryExperiment, MemoryExperimentConfig -from .noise import NoiseModel, NoNoiseModel, DepolarizingNoiseModel +from .noise import DepolarizingNoiseModel, NoiseModel, NoNoiseModel __all__ = [ + "DepolarizingNoiseModel", "MemoryExperiment", "MemoryExperimentConfig", - "NoiseModel", "NoNoiseModel", - "DepolarizingNoiseModel", + "NoiseModel", ] - diff --git a/ACID/src/acid/memory_experiment/builder.py b/ACID/src/acid/memory_experiment/builder.py index 3ae416b..0e19cbf 100644 --- a/ACID/src/acid/memory_experiment/builder.py +++ b/ACID/src/acid/memory_experiment/builder.py @@ -1,7 +1,7 @@ from __future__ import annotations +from collections.abc import Iterable from dataclasses import dataclass -from typing import Iterable, List, Tuple @dataclass @@ -13,7 +13,8 @@ class StimBuilder: - Tracks current measurement count to resolve rec[-k] offsets at DETECTOR/OBS lines. - Provides helpers to append operations and get rec indices. """ - lines: List[str] + + lines: list[str] _rec_count: int = 0 _tick_count: int = 0 @@ -41,16 +42,16 @@ def RX(self, qubits: Iterable[int]) -> None: if qs: self.append_line("RX " + " ".join(str(q) for q in qs)) - def CX(self, pairs: List[Tuple[int, int]]) -> None: + def CX(self, pairs: list[tuple[int, int]]) -> None: if not pairs: return - flat: List[str] = [] + flat: list[str] = [] for c, t in pairs: flat.append(str(int(c))) flat.append(str(int(t))) self.append_line("CX " + " ".join(flat)) - def MX(self, qubits: List[int]) -> List[int]: + def MX(self, qubits: list[int]) -> list[int]: qs = list(map(int, qubits)) if not qs: return [] @@ -59,7 +60,7 @@ def MX(self, qubits: List[int]) -> List[int]: self._rec_count += len(qs) return recs - def MZ(self, qubits: List[int]) -> List[int]: + def MZ(self, qubits: list[int]) -> list[int]: qs = list(map(int, qubits)) if not qs: return [] @@ -68,14 +69,14 @@ def MZ(self, qubits: List[int]) -> List[int]: self._rec_count += len(qs) return recs - def MPP_terms(self, terms: List[List[Tuple[str, int]]]) -> List[int]: + def MPP_terms(self, terms: list[list[tuple[str, int]]]) -> list[int]: """ Emit an MPP instruction where each term is [[('X',q1),('X',q2)], [('Z',q3),...], ...]. Returns the list of rec indices produced. """ if not terms: return [] - parts: List[str] = [] + parts: list[str] = [] for term in terms: if not term: continue @@ -90,7 +91,7 @@ def MPP_terms(self, terms: List[List[Tuple[str, int]]]) -> List[int]: def QUBIT_COORDS(self, q: int, x: float, y: float) -> None: self.append_line(f"QUBIT_COORDS({x:.6g}, {y:.6g}) {int(q)}") - def DETECTOR(self, rec_indices: List[int]) -> None: + def DETECTOR(self, rec_indices: list[int]) -> None: """Emit a DETECTOR referencing given absolute rec indices (0-based).""" if not rec_indices: return @@ -99,10 +100,9 @@ def DETECTOR(self, rec_indices: List[int]) -> None: parts = [f"rec[{r}]" for r in rels] self.append_line("DETECTOR " + " ".join(parts)) - def OBSERVABLE_INCLUDE(self, obs_index: int, rec_indices: List[int]) -> None: + def OBSERVABLE_INCLUDE(self, obs_index: int, rec_indices: list[int]) -> None: if not rec_indices: return rels = [-(self._rec_count - ri) for ri in rec_indices] parts = [f"rec[{r}]" for r in rels] self.append_line(f"OBSERVABLE_INCLUDE({int(obs_index)}) " + " ".join(parts)) - diff --git a/ACID/src/acid/memory_experiment/embedding_utils.py b/ACID/src/acid/memory_experiment/embedding_utils.py index 7b82643..b7c522d 100644 --- a/ACID/src/acid/memory_experiment/embedding_utils.py +++ b/ACID/src/acid/memory_experiment/embedding_utils.py @@ -1,18 +1,21 @@ from __future__ import annotations -from typing import Iterable, List, Tuple +from collections.abc import Iterable from acid.embedding import Embedding -def data_bbox_xy(embedding: Embedding, data_ids: Iterable[int]) -> Tuple[float, float, float, float]: +def data_bbox_xy( + embedding: Embedding, data_ids: Iterable[int] +) -> tuple[float, float, float, float]: """Return (min_x, min_y, max_x, max_y) bbox of given data qubits using embedding coords.""" - xs: List[float] = [] - ys: List[float] = [] + xs: list[float] = [] + ys: list[float] = [] for q in data_ids: a, b, c = embedding.id_to_tuple(int(q)) x, y = embedding.coords(a, b, c) - xs.append(float(x)); ys.append(float(y)) + xs.append(float(x)) + ys.append(float(y)) if not xs: return 0.0, 0.0, 0.0, 0.0 return min(xs), min(ys), max(xs), max(ys) @@ -25,7 +28,7 @@ def place_ancillas_right_of_bbox( *, dx: float = 1.0, dy: float = 1.0, -) -> Tuple[List[int], List[int], List[Tuple[int, float, float]]]: +) -> tuple[list[int], list[int], list[tuple[int, float, float]]]: """ Return (zero_ancilla_ids, plus_ancilla_ids, qubit_coord_triplets) placing 2k ancillas in a vertical column to the right of the data bbox with a blank row between each pair. @@ -43,12 +46,13 @@ def place_ancillas_right_of_bbox( zeros = [start + 2 * i for i in range(k)] plus = [start + 2 * i + 1 for i in range(k)] anc_ids = [] - anc_ids.extend(zeros); anc_ids.extend(plus) + anc_ids.extend(zeros) + anc_ids.extend(plus) - x0, y0, x1, y1 = data_bbox_xy(embedding, data_ids) + _x0, y0, x1, _y1 = data_bbox_xy(embedding, data_ids) x_right = x1 + abs(dx) y_min = y0 - coords: List[Tuple[int, float, float]] = [] + coords: list[tuple[int, float, float]] = [] for i in range(k): # place zero-ancilla then plus-ancilla with a blank row (dy) between pairs y_z = y_min + float(3 * i) * abs(dy) @@ -56,4 +60,3 @@ def place_ancillas_right_of_bbox( coords.append((zeros[i], x_right, y_z)) coords.append((plus[i], x_right, y_x)) return zeros, plus, coords - diff --git a/ACID/src/acid/memory_experiment/experiment.py b/ACID/src/acid/memory_experiment/experiment.py index 2aeaae5..0d56d7c 100644 --- a/ACID/src/acid/memory_experiment/experiment.py +++ b/ACID/src/acid/memory_experiment/experiment.py @@ -1,22 +1,20 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Dict, List, Tuple -from acid.embedding import Embedding from acid.defects.defective_code import DefectiveCode from acid.defects.syndrome_extraction_circuit import SyndromeExtractionCircuit - +from acid.embedding import Embedding from acid.memory_experiment.builder import StimBuilder from acid.memory_experiment.embedding_utils import place_ancillas_right_of_bbox from acid.memory_experiment.noise import NoiseModel, NoNoiseModel +from .observables import plan_observables +from .product_detectors import plan_product_detectors from .rec_log import MeasurementLog +from .registry import DetectorRegistry from .schedule_index import ScheduleIndex from .single_detectors import plan_quasi_detectors -from .product_detectors import plan_product_detectors -from .observables import plan_observables -from .registry import DetectorRegistry @dataclass @@ -51,18 +49,18 @@ def __init__( self.L = len(self.circuit.layers) self.registry = DetectorRegistry() - def _root_qubits_by_basis(self, layer) -> Tuple[List[int], List[int]]: + def _root_qubits_by_basis(self, layer) -> tuple[list[int], list[int]]: return layer.roots_by_basis() - def _root_qubit_map(self, layer) -> Dict[int, str]: - m: Dict[int, str] = {} + def _root_qubit_map(self, layer) -> dict[int, str]: + m: dict[int, str] = {} for stab, shed in layer.chosen.items(): root_q = stab.qubit_map[shed.root] m[root_q] = stab.label return m - def _entangling_pairs(self) -> List[Tuple[int, int]]: - pairs: List[Tuple[int, int]] = [] + def _entangling_pairs(self) -> list[tuple[int, int]]: + pairs: list[tuple[int, int]] = [] for i in range(self.k): for q in self._Lx[i].x_support(): pairs.append((-(i + 1), int(q))) @@ -81,25 +79,30 @@ def build( # Prepend base visualisation overlay = self.dcode.visualisation_stim(self.embedding) overlay_lines = overlay.rstrip().splitlines() - overlay_tick_count = sum(1 for ln in overlay_lines if ln.strip() == 'TICK') - b = StimBuilder(lines=list(overlay_lines)) - b._tick_count = overlay_tick_count # type: ignore[attr-defined] + overlay_tick_count = sum(1 for ln in overlay_lines if ln.strip() == "TICK") + # helper object to build the stim circuit + stim_builder = StimBuilder(lines=list(overlay_lines)) + stim_builder._tick_count = overlay_tick_count # type: ignore[attr-defined] # Ancillas (only if doing state prep) n = self.dcode.base_code.num_qubits - zeros: List[int] = [] - plus: List[int] = [] - anc_coords: List[Tuple[int, float, float]] = [] + zeros: list[int] = [] + plus: list[int] = [] + anc_coords: list[tuple[int, float, float]] = [] if include_state_prep: zeros, plus, anc_coords = place_ancillas_right_of_bbox( - self.embedding, list(range(n)), self.k, dx=self.cfg.ancilla_dx, dy=self.cfg.ancilla_dy + self.embedding, + list(range(n)), + self.k, + dx=self.cfg.ancilla_dx, + dy=self.cfg.ancilla_dy, ) for q, x, y in anc_coords: - b.QUBIT_COORDS(q, x, y) + stim_builder.QUBIT_COORDS(q, x, y) if zeros: - b.R(zeros) + stim_builder.R(zeros) if plus: - b.RX(plus) + stim_builder.RX(plus) log = MeasurementLog() @@ -108,22 +111,22 @@ def build( # X pass for lab in sorted(self.dcode.quasi_labels): # type: ignore[attr-defined] typ, supp = self.dcode.quasi_support(lab) - if typ != 'X' or not include_x_detectors: + if typ != "X" or not include_x_detectors: continue term = [[(typ, q) for q in supp]] - rec = b.MPP_terms(term)[0] - log.record_init_mpp('X', lab, rec) + rec = stim_builder.MPP_terms(term)[0] + log.record_init_mpp("X", lab, rec) # Z pass for lab in sorted(self.dcode.quasi_labels): # type: ignore[attr-defined] typ, supp = self.dcode.quasi_support(lab) - if typ != 'Z' or not include_z_detectors: + if typ != "Z" or not include_z_detectors: continue term = [[(typ, q) for q in supp]] - rec = b.MPP_terms(term)[0] - log.record_init_mpp('Z', lab, rec) + rec = stim_builder.MPP_terms(term)[0] + log.record_init_mpp("Z", lab, rec) # Entangle (noiseless), only if doing state prep - ent_pairs: List[Tuple[int, int]] = [] + ent_pairs: list[tuple[int, int]] = [] if include_state_prep: ent_pairs_placeholder = self._entangling_pairs() anc_zero = zeros @@ -134,8 +137,8 @@ def build( if t < 0: t = anc_zero[-t - 1 - self.k] ent_pairs.append((int(c), int(t))) - b.CX([(int(c), int(t))]) - b.tick() + stim_builder.CX([(int(c), int(t))]) + stim_builder.tick() # Noisy rounds: R cycles over L layers for r in range(1, self.cfg.R + 1): @@ -144,74 +147,78 @@ def build( for step in Lk.collect_cx_stim(): if step: pairs = [(int(c), int(tg)) for (c, tg) in step] - b.CX(pairs) - self.noise.apply_after_gate(b, "CX", pairs) - b.tick() + stim_builder.CX(pairs) + self.noise.apply_after_gate(stim_builder, "CX", pairs) + stim_builder.tick() # Measure roots x_roots, z_roots = self._root_qubits_by_basis(Lk) if x_roots: - self.noise.apply_before_measure(b, 'X', sorted(x_roots)) + self.noise.apply_before_measure(stim_builder, "X", sorted(x_roots)) xr = sorted(x_roots) - x_recs = b.MX(xr) + x_recs = stim_builder.MX(xr) for q, rec in zip(xr, x_recs): - log.record_layer_meas(r, t, 'X', int(q), int(rec)) + log.record_layer_meas(r, t, "X", int(q), int(rec)) if z_roots: - self.noise.apply_before_measure(b, 'Z', sorted(z_roots)) + self.noise.apply_before_measure(stim_builder, "Z", sorted(z_roots)) zr = sorted(z_roots) - z_recs = b.MZ(zr) + z_recs = stim_builder.MZ(zr) for q, rec in zip(zr, z_recs): - log.record_layer_meas(r, t, 'Z', int(q), int(rec)) + log.record_layer_meas(r, t, "Z", int(q), int(rec)) # TICK after measurement - b.tick() + stim_builder.tick() # Resets if x_roots: - b.RX(sorted(x_roots)) - self.noise.apply_after_reset(b, sorted(x_roots), basis='X') + stim_builder.RX(sorted(x_roots)) + self.noise.apply_after_reset( + stim_builder, sorted(x_roots), basis="X" + ) if z_roots: - b.R(sorted(z_roots)) - self.noise.apply_after_reset(b, sorted(z_roots), basis='Z') - b.tick() + stim_builder.R(sorted(z_roots)) + self.noise.apply_after_reset( + stim_builder, sorted(z_roots), basis="Z" + ) + stim_builder.tick() # Expand steps = Lk.collect_cx_stim() for step in reversed(steps): if step: pairs = [(int(c), int(tg)) for (c, tg) in step] - b.CX(pairs) - self.noise.apply_after_gate(b, "CX", pairs) - b.tick() - + stim_builder.CX(pairs) + self.noise.apply_after_gate(stim_builder, "CX", pairs) + stim_builder.tick() + # Unentangle and final MPP only if doing state prep if include_state_prep: # Unentangle (reverse, noiseless) for c, t in reversed(ent_pairs): - b.CX([(int(c), int(t))]) - b.tick() + stim_builder.CX([(int(c), int(t))]) + stim_builder.tick() # Final MPP: X then Z for lab in sorted(self.dcode.quasi_labels): # type: ignore[attr-defined] typ, supp = self.dcode.quasi_support(lab) - if typ != 'X' or not include_x_detectors: + if typ != "X" or not include_x_detectors: continue term = [[(typ, q) for q in supp]] - rec = b.MPP_terms(term)[0] - log.record_final_mpp('X', lab, rec) - b.tick() + rec = stim_builder.MPP_terms(term)[0] + log.record_final_mpp("X", lab, rec) + stim_builder.tick() for lab in sorted(self.dcode.quasi_labels): # type: ignore[attr-defined] typ, supp = self.dcode.quasi_support(lab) - if typ != 'Z' or not include_z_detectors: + if typ != "Z" or not include_z_detectors: continue term = [[(typ, q) for q in supp]] - rec = b.MPP_terms(term)[0] - log.record_final_mpp('Z', lab, rec) - b.tick() + rec = stim_builder.MPP_terms(term)[0] + log.record_final_mpp("Z", lab, rec) + stim_builder.tick() # Ancilla observables (noiseless) — record final ancilla recs, but don't emit yet - z_anc_recs: List[int] = [] - x_anc_recs: List[int] = [] + z_anc_recs: list[int] = [] + x_anc_recs: list[int] = [] if include_state_prep: if zeros and include_z_detectors: - z_anc_recs = b.MZ(zeros) + z_anc_recs = stim_builder.MZ(zeros) if plus and include_x_detectors: - x_anc_recs = b.MX(plus) + x_anc_recs = stim_builder.MX(plus) # Plan and emit detectors (offline) # Detectors/observables only if requested (and typically require state prep) @@ -240,18 +247,20 @@ def build( ) if debug: try: - print(f"[detectors] planning: single_quasi={len(quasi_plan.rec_sets)}") + print( + f"[detectors] planning: single_quasi={len(quasi_plan.rec_sets)}" + ) print(f"[detectors] planning: product={len(prod_plan.rec_sets)}") except Exception: pass next_id = 0 for recs, info in zip(quasi_plan.rec_sets, quasi_plan.infos): - b.DETECTOR(recs) + stim_builder.DETECTOR(recs) info.id = next_id next_id += 1 self.registry.add(info) for recs, info in zip(prod_plan.rec_sets, prod_plan.infos): - b.DETECTOR(recs) + stim_builder.DETECTOR(recs) info.id = next_id next_id += 1 self.registry.add(info) @@ -272,10 +281,10 @@ def build( ) obs_index = 0 for recs in obs_z_sets: - b.OBSERVABLE_INCLUDE(obs_index, recs) + stim_builder.OBSERVABLE_INCLUDE(obs_index, recs) obs_index += 1 for recs in obs_x_sets: - b.OBSERVABLE_INCLUDE(obs_index, recs) + stim_builder.OBSERVABLE_INCLUDE(obs_index, recs) obs_index += 1 - return "\n".join(b.lines) + "\n" + return "\n".join(stim_builder.lines) + "\n" diff --git a/ACID/src/acid/memory_experiment/noise.py b/ACID/src/acid/memory_experiment/noise.py index 89a9ca6..dfab181 100644 --- a/ACID/src/acid/memory_experiment/noise.py +++ b/ACID/src/acid/memory_experiment/noise.py @@ -1,7 +1,7 @@ from __future__ import annotations +from collections.abc import Iterable from dataclasses import dataclass -from typing import Dict, Iterable, List, Tuple class StimBuilderProtocol: @@ -20,33 +20,38 @@ class NoiseModel: on the specified targets. """ - def apply_after_gate(self, builder: StimBuilderProtocol, gate: str, targets: List[Tuple[int, ...]]) -> None: + def apply_after_gate( + self, builder: StimBuilderProtocol, gate: str, targets: list[tuple[int, ...]] + ) -> None: """Called after a gate is emitted. - gate: gate name (e.g., "CX"). - targets: list of tuples (e.g., [(c,t), ...] for a 2q gate). """ - return None + return - def apply_after_reset(self, builder: StimBuilderProtocol, qubits: Iterable[int], *, basis: str = 'Z') -> None: + def apply_after_reset( + self, builder: StimBuilderProtocol, qubits: Iterable[int], *, basis: str = "Z" + ) -> None: """Called after a reset line on the given qubits. basis: 'Z' for R (|0>), 'X' for RX (|+>) """ - return None + return - def apply_before_measure(self, builder: StimBuilderProtocol, basis: str, qubits_or_terms: Iterable) -> None: + def apply_before_measure( + self, builder: StimBuilderProtocol, basis: str, qubits_or_terms: Iterable + ) -> None: """Called immediately before measurement. - basis: 'X' or 'Z' for MX/MZ; 'PP' for MPP. - qubits_or_terms: for MX/MZ it is a list of qubit ids; for MPP a list of terms, each term is a list of (pauli, qid). """ - return None + return class NoNoiseModel(NoiseModel): """No-op noise model.""" - pass @dataclass @@ -63,35 +68,44 @@ class DepolarizingNoiseModel(NoiseModel): MPP currently left noiseless, but can be extended. """ - p1: float = 0.0 # single-qubit flip prob (pre-measure and post-reset; anti-commuting) + + p1: float = ( + 0.0 # single-qubit flip prob (pre-measure and post-reset; anti-commuting) + ) p2: float = 0.0 # two-qubit depolarizing after CX - def apply_after_gate(self, builder: StimBuilderProtocol, gate: str, targets: List[Tuple[int, ...]]) -> None: + def apply_after_gate( + self, builder: StimBuilderProtocol, gate: str, targets: list[tuple[int, ...]] + ) -> None: if self.p2 <= 0: return if gate.upper() in ("CX", "CNOT"): for c, t in targets: builder.append_line(f"DEPOLARIZE2({self.p2}) {c} {t}") - def apply_before_measure(self, builder: StimBuilderProtocol, basis: str, qubits_or_terms: Iterable) -> None: + def apply_before_measure( + self, builder: StimBuilderProtocol, basis: str, qubits_or_terms: Iterable + ) -> None: if self.p1 <= 0: return # Apply flips that anti-commute with the measured basis - if basis.upper() == 'X': # MX + if basis.upper() == "X": # MX for q in list(qubits_or_terms): builder.append_line(f"Z_ERROR({self.p1}) {int(q)}") - elif basis.upper() == 'Z': # M / MZ + elif basis.upper() == "Z": # M / MZ for q in list(qubits_or_terms): builder.append_line(f"X_ERROR({self.p1}) {int(q)}") # For 'PP' (MPP), extend if needed. - def apply_after_reset(self, builder: StimBuilderProtocol, qubits: Iterable[int], *, basis: str = 'Z') -> None: + def apply_after_reset( + self, builder: StimBuilderProtocol, qubits: Iterable[int], *, basis: str = "Z" + ) -> None: if self.p1 <= 0: return # Apply flips that anti-commute with the prepared basis - if basis.upper() == 'Z': # R + if basis.upper() == "Z": # R for q in list(qubits): builder.append_line(f"X_ERROR({self.p1}) {int(q)}") - elif basis.upper() == 'X': # RX + elif basis.upper() == "X": # RX for q in list(qubits): builder.append_line(f"Z_ERROR({self.p1}) {int(q)}") diff --git a/ACID/src/acid/memory_experiment/observables.py b/ACID/src/acid/memory_experiment/observables.py index 802b5ca..a025f70 100644 --- a/ACID/src/acid/memory_experiment/observables.py +++ b/ACID/src/acid/memory_experiment/observables.py @@ -1,10 +1,8 @@ from __future__ import annotations -from typing import List, Tuple - +from acid.defects.defective_code import DefectiveCode from acid.pauli import PauliString from acid.scheduling.types import SyndromeExtractionLayer -from acid.defects.defective_code import DefectiveCode from .rec_log import MeasurementLog from .schedule_index import ScheduleIndex @@ -13,60 +11,63 @@ def plan_observables( *, dcode: DefectiveCode, - layers: List[SyndromeExtractionLayer], + layers: list[SyndromeExtractionLayer], sched: ScheduleIndex, log: MeasurementLog, R: int, - Lx_mid: List[PauliString], - Lz_mid: List[PauliString], - ancilla_recs_x: List[int], - ancilla_recs_z: List[int], + Lx_mid: list[PauliString], + Lz_mid: list[PauliString], + ancilla_recs_x: list[int], + ancilla_recs_z: list[int], include_x: bool = True, include_z: bool = True, -) -> Tuple[List[List[int]], List[List[int]]]: +) -> tuple[list[list[int]], list[list[int]]]: L = len(layers) - obs_z: List[List[int]] = [] + obs_z: list[list[int]] = [] if include_z: for i, anc_rec in enumerate(ancilla_recs_z): if i >= len(Lz_mid): break Pmid = Lz_mid[i] - recs: List[int] = [] + recs: list[int] = [] for r in range(1, R + 1): for t in range(L): Pc = layers[t].propagate(Pmid) S = set(Pc.z_support()) - root_map = log.per_layer.get((r, t, 'Z'), {}) - root_map_other = log.per_layer.get((r, t, 'X'), {}) + root_map = log.per_layer.get((r, t, "Z"), {}) + root_map_other = log.per_layer.get((r, t, "X"), {}) for q in S: if q in root_map_other: - raise RuntimeError(f"Observable-Z support overlaps X measurement at round={r}, layer={t}, qubit={q}") + raise RuntimeError( + f"Observable-Z support overlaps X measurement at round={r}, layer={t}, qubit={q}" + ) if q in root_map: recs.append(int(root_map[q])) recs.append(int(anc_rec)) obs_z.append(recs) - obs_x: List[List[int]] = [] + obs_x: list[list[int]] = [] if include_x: for i, anc_rec in enumerate(ancilla_recs_x): if i >= len(Lx_mid): break Pmid = Lx_mid[i] - recs: List[int] = [] + recs: list[int] = [] for r in range(1, R + 1): for t in range(L): Pc = layers[t].propagate(Pmid) S = set(Pc.x_support()) - root_map = log.per_layer.get((r, t, 'X'), {}) - root_map_other = log.per_layer.get((r, t, 'Z'), {}) + root_map = log.per_layer.get((r, t, "X"), {}) + root_map_other = log.per_layer.get((r, t, "Z"), {}) for q in S: if q in root_map_other: - raise RuntimeError(f"Observable-X support overlaps Z measurement at round={r}, layer={t}, qubit={q}") + raise RuntimeError( + f"Observable-X support overlaps Z measurement at round={r}, layer={t}, qubit={q}" + ) if q in root_map: recs.append(int(root_map[q])) recs.append(int(anc_rec)) obs_x.append(recs) return obs_z, obs_x - diff --git a/ACID/src/acid/memory_experiment/product_detectors.py b/ACID/src/acid/memory_experiment/product_detectors.py index b0bcfb4..dbd82fe 100644 --- a/ACID/src/acid/memory_experiment/product_detectors.py +++ b/ACID/src/acid/memory_experiment/product_detectors.py @@ -1,12 +1,11 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Dict, List, Optional, Set, Tuple from acid.analysis.schedule import analyze_layers -from acid.scheduling.types import SyndromeExtractionLayer from acid.defects.defective_code import DefectiveCode from acid.pauli import PauliString +from acid.scheduling.types import SyndromeExtractionLayer from .rec_log import MeasurementLog from .schedule_index import ScheduleIndex @@ -14,13 +13,14 @@ def _lin_idx(L: int, r: int, t: int) -> int: + # Flatten (round, layer) onto a single timeline index. return (int(r) - 1) * int(L) + int(t) def plan_product_detectors( *, dcode: DefectiveCode, - layers: List[SyndromeExtractionLayer], + layers: list[SyndromeExtractionLayer], sched: ScheduleIndex, log: MeasurementLog, R: int, @@ -29,71 +29,134 @@ def plan_product_detectors( debug: bool = False, ) -> DetectorPlan: + # L: layers per round, used for linearizing schedule coordinates. L = len(layers) plan = DetectorPlan() - products = [p for p in dcode.products_list() if len(p.members) > 1 and ((p.pauli_type == 'X' and include_x) or (p.pauli_type == 'Z' and include_z))] + products = [ + p + for p in dcode.products_list() + if len(p.members) > 1 + and ((p.pauli_type == "X" and include_x) or (p.pauli_type == "Z" and include_z)) + ] if not products: return plan + # Precompute per-product completion layers within a round. prod_plan = build_product_plan(dcode, layers) # Precompute mid-cycle PauliStrings for all members by basis # We'll build per-product cache on the fly next_id = 0 - for p in products: - basis = p.pauli_type - members = list(p.members) - # Build completion sequence: B0 (init), then for each round the sorted completions, then BN (final) - periodic = sorted(prod_plan.completions.get(p.label, [])) - completions: List[Tuple[str, Optional[Tuple[int, int]], Dict[str, Tuple[int, int]], Optional[Tuple[int, int]]]] = [] - # Tuple fields: (kind, B_rt, member_latest, A_rt) - completions.append(('init_mpp', None, {}, None)) - for r in range(1, R + 1): - for t_star in periodic: - # member_latest: latest (r, t_m) for each member <= t_star - member_latest: Dict[str, Tuple[int, int]] = {} - for m in members: - ts_all = sched.contracting_ts.get(m, []) - ts_le = [t for t in ts_all if t <= t_star] + for current_product in products: + basis = current_product.pauli_type + members = list(current_product.members) + # Build completion sequence B_i: + # B0 = init_mpp, intermediate B_i = per-round completion events, + # BN = final_mpp. Each contract event carries member latest times c_q + # and A_i (earliest among those latest times). + sorted_completion_times = sorted( + prod_plan.completions.get(current_product.label, []) + ) + completions: list[ + tuple[ + str, # kind + tuple[int, int] | None, # (round, layer) product completion time + dict[ + str, tuple[int, int] + ], # member -> most recent (round, layer) contraction time + tuple[int, int] + | None, # earliest among those most recent contraction times + ] + ] = [] + completions.append(("init_mpp", None, {}, None)) + for round_number in range(1, R + 1): + for completion_time in sorted_completion_times: + # we want the last time each member was measured in this round, up to the + # completion time. + member_to_lastest_time_measured: dict[str, tuple[int, int]] = {} + for product_member in members: + ts_all = sched.contracting_ts.get(product_member, []) + ts_le = [t for t in ts_all if t <= completion_time] if not ts_le: - raise RuntimeError(f"Product completion invariant violated: member {m} not measured by t*={t_star} in round {r} for product {p.label}") - t_m = max(ts_le) - member_latest[m] = (r, t_m) - # A_i: earliest among member_latest - A_rt = min(member_latest.values(), key=lambda rt: _lin_idx(L, rt[0], rt[1])) - completions.append(('contract', (r, t_star), member_latest, A_rt)) - completions.append(('final_mpp', None, {}, None)) + raise RuntimeError( + f"Product completion invariant violated: member {product_member} not " + f"measured by t*={completion_time} in round {round_number} for product " + f"{current_product.label}" + ) + latest_measurement_time = max(ts_le) + member_to_lastest_time_measured[product_member] = ( + round_number, + latest_measurement_time, + ) + earliest_member_time = min( + member_to_lastest_time_measured.values(), + key=lambda rt: _lin_idx(L, rt[0], rt[1]), + ) + completions.append( + ( + "contract", + (round_number, completion_time), + member_to_lastest_time_measured, + earliest_member_time, + ) + ) + completions.append(("final_mpp", None, {}, None)) if debug: try: - print(f"[product-debug] Product {p.label} basis={basis} members={len(members)}") - for idx, (kind, B_rt, member_latest, A_rt) in enumerate(completions): - if kind == 'contract': - print(f" - B[{idx}] kind=contract B_rt={B_rt} A_rt={A_rt} c_q={{" + ", ".join(f"{m}:{rt}" for m, rt in member_latest.items()) + "}}") + print( + f"[product-debug] Product {current_product.label} basis={basis} members={len(members)}" + ) + for idx, ( + kind, + B_rt, + member_to_lastest_time_measured, + earliest_member_time, + ) in enumerate(completions): + if kind == "contract": + print( + f" - B[{idx}] kind=contract B_rt={B_rt} A_rt={earliest_member_time} c_q={{" + + ", ".join( + f"{m}:{rt}" + for m, rt in member_to_lastest_time_measured.items() + ) + + "}}" + ) else: print(f" - B[{idx}] kind={kind}") except Exception: pass # Helper: active support at a layer by XOR of supports of active members - def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dict[str, Tuple[int, int]]) -> Set[int]: + def active_support_at( + r: int, + t: int, + cqi: dict[str, tuple[int, int]], + cqi1: dict[str, tuple[int, int]], + ) -> set[int]: idx = _lin_idx(L, r, t) - acc: Set[int] = set() + acc: set[int] = set() for m in members: # previous/next contraction indices prev_rt = cqi.get(m) next_rt = cqi1.get(m) - prev_idx = -1 if prev_rt is None else _lin_idx(L, prev_rt[0], prev_rt[1]) - next_idx = R * L if next_rt is None else _lin_idx(L, next_rt[0], next_rt[1]) + prev_idx = ( + -1 if prev_rt is None else _lin_idx(L, prev_rt[0], prev_rt[1]) + ) + next_idx = ( + R * L if next_rt is None else _lin_idx(L, next_rt[0], next_rt[1]) + ) if prev_idx < idx <= next_idx: # propagate member mid-cycle Pauli - typ, supp = dcode.quasi_support(m) + _typ, supp = dcode.quasi_support(m) n = dcode.base_code.num_qubits - Pmid = PauliString.from_supports(supp if basis == 'X' else [], [] if basis == 'X' else supp, n) + Pmid = PauliString.from_supports( + supp if basis == "X" else [], [] if basis == "X" else supp, n + ) Pc = layers[t].propagate(Pmid) - S = set(Pc.x_support() if basis == 'X' else Pc.z_support()) + S = set(Pc.x_support() if basis == "X" else Pc.z_support()) # XOR with accumulator if not acc: acc = set(S) @@ -111,37 +174,50 @@ def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dic # Synthesize detectors per adjacent completion pair for i in range(len(completions) - 1): kind_a, B_rt_a, latest_a, A_rt_a = completions[i] - kind_b, B_rt_b, latest_b, A_rt_b = completions[i + 1] + kind_b, B_rt_b, latest_b, _A_rt_b = completions[i + 1] - # Determine window bounds in linear indices + # Detector window is (A_i, B_{i+1}] in linearized schedule time. A_lin = -1 if A_rt_a is None else _lin_idx(L, A_rt_a[0], A_rt_a[1]) B_next_lin = R * L if B_rt_b is None else _lin_idx(L, B_rt_b[0], B_rt_b[1]) - # c_q for this and next completion + # c_q maps member -> latest contraction time at B_i/B_{i+1}. cqi = latest_a # may be empty for init cqi1 = latest_b # may be empty for final - recs: List[int] = [] - intervening_layers: List[Tuple[int, int]] = [] + recs: list[int] = [] + intervening_layers: list[tuple[int, int]] = [] if debug: try: - print(f" [window {i}] start={{kind:{kind_a},A_rt:{A_rt_a},B_rt:{B_rt_a}}} -> end={{kind:{kind_b},B_rt:{B_rt_b}}}") + print( + f" [window {i}] start={{kind:{kind_a},A_rt:{A_rt_a},B_rt:{B_rt_a}}} -> end={{kind:{kind_b},B_rt:{B_rt_b}}}" + ) if latest_a: - print(" c_q_i = {" + ", ".join(f"{m}:{rt}" for m, rt in latest_a.items()) + "}") + print( + " c_q_i = {" + + ", ".join(f"{m}:{rt}" for m, rt in latest_a.items()) + + "}" + ) if latest_b: - print(" c_q_ip1 = {" + ", ".join(f"{m}:{rt}" for m, rt in latest_b.items()) + "}") + print( + " c_q_ip1 = {" + + ", ".join(f"{m}:{rt}" for m, rt in latest_b.items()) + + "}" + ) except Exception: pass - # (1) First detector only: include init MPP product + # (1) First window starts from an init MPP parity snapshot. if i == 0: - for m in members: - rec0 = log.init_mpp[basis][m] + for product_member in members: + rec0 = log.init_mpp[basis][product_member] recs.append(int(rec0)) - # (2) Per-layer contributions for A_i < l ≤ B_{i+1} - layer_summaries: List[Tuple[int, int, int, int]] = [] # (r,t, |S|, added_recs) + # (2) For each layer in the window, add same-basis root recs on the + # active propagated product support. + layer_summaries: list[ + tuple[int, int, int, int] + ] = [] # (r,t, |S|, added_recs) for idx in range(A_lin + 1, min(B_next_lin, R * L) + 1): if idx >= R * L: break @@ -149,11 +225,15 @@ def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dic t_i = idx % L S = active_support_at(r_i, t_i, cqi, cqi1) root_same = log.per_layer.get((r_i, t_i, basis), {}) - root_other = log.per_layer.get((r_i, t_i, 'Z' if basis == 'X' else 'X'), {}) - # Fail fast if any opposite-basis root overlaps + root_other = log.per_layer.get( + (r_i, t_i, "Z" if basis == "X" else "X"), {} + ) + # Opposite-basis overlap indicates an invalid detector composition. if any((q in root_other) for q in S): bad = [q for q in S if q in root_other] - raise RuntimeError(f"Product {p.label} support overlaps opposite-basis roots at r={r_i}, t={t_i}, qubits={bad}") + raise RuntimeError( + f"Product {current_product.label} support overlaps opposite-basis roots at r={r_i}, t={t_i}, qubits={bad}" + ) added = 0 for q in S: if q in root_same: @@ -163,10 +243,10 @@ def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dic if S: intervening_layers.append((r_i, t_i)) - # (3) Final window includes final product from final MPP - if kind_b == 'final_mpp': - for m in members: - recf = log.final_mpp[basis][m] + # (3) Last window closes with final MPP parity snapshot. + if kind_b == "final_mpp": + for product_member in members: + recf = log.final_mpp[basis][product_member] recs.append(int(recf)) if not recs: @@ -174,11 +254,19 @@ def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dic info = DetectorInfo( id=next_id, - kind='product', - label=p.label, + kind="product", + label=current_product.label, basis=None, - start={'type': kind_a, 'round': A_rt_a[0] if A_rt_a else None, 'layer': A_rt_a[1] if A_rt_a else None}, - end={'type': kind_b, 'round': B_rt_b[0] if B_rt_b else None, 'layer': B_rt_b[1] if B_rt_b else None}, + start={ + "type": kind_a, + "round": A_rt_a[0] if A_rt_a else None, + "layer": A_rt_a[1] if A_rt_a else None, + }, + end={ + "type": kind_b, + "round": B_rt_b[0] if B_rt_b else None, + "layer": B_rt_b[1] if B_rt_b else None, + }, intervening=intervening_layers, recs=list(recs), ) @@ -188,8 +276,8 @@ def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dic if debug: try: - print(f" layers (r,t): active_qubits -> added_recs") - for (r_i, t_i, ssz, added) in layer_summaries: + print(" layers (r,t): active_qubits -> added_recs") + for r_i, t_i, ssz, added in layer_summaries: print(f" (r={r_i}, t={t_i}): {ssz} -> {added}") except Exception: pass @@ -199,16 +287,25 @@ def active_support_at(r: int, t: int, cqi: Dict[str, Tuple[int, int]], cqi1: Dic @dataclass class ProductPlan: - members: Dict[str, Set[str]] # prod_label -> set(member labels) - completions: Dict[str, List[int]] # prod_label -> list of layer indices where completed + members: dict[str, set[str]] # prod_label -> set(member labels) + completions: dict[ + str, list[int] + ] # prod_label -> list of layer indices where completed -def build_product_plan(dcode: DefectiveCode, layers: List[SyndromeExtractionLayer]) -> ProductPlan: +def build_product_plan( + dcode: DefectiveCode, layers: list[SyndromeExtractionLayer] +) -> ProductPlan: """ Use analyze_layers to determine per-layer product completion points. + + product_completions[label] is a list of layer indices t where all members + needed for that product have been measured by layer t in a round. """ prods = dcode.products_list() - prod_members: Dict[str, Set[str]] = {p.label: set(p.members) for p in prods if len(p.members) > 1} + prod_members: dict[str, set[str]] = { + p.label: set(p.members) for p in prods if len(p.members) > 1 + } result = analyze_layers(prod_members, layers, interesting_labels=None) - completions: Dict[str, List[int]] = result['product_completions'] + completions: dict[str, list[int]] = result["product_completions"] return ProductPlan(members=prod_members, completions=completions) diff --git a/ACID/src/acid/memory_experiment/rec_log.py b/ACID/src/acid/memory_experiment/rec_log.py index 3fe889e..2eec66e 100644 --- a/ACID/src/acid/memory_experiment/rec_log.py +++ b/ACID/src/acid/memory_experiment/rec_log.py @@ -1,7 +1,6 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Dict, List, Tuple @dataclass @@ -13,9 +12,14 @@ class MeasurementLog: - final_mpp: per-basis dict of quasi label -> rec index - per_layer: mapping (round_idx, layer_idx, basis) -> {root_qid -> rec} """ - init_mpp: Dict[str, Dict[str, int]] = field(default_factory=lambda: {'X': {}, 'Z': {}}) - final_mpp: Dict[str, Dict[str, int]] = field(default_factory=lambda: {'X': {}, 'Z': {}}) - per_layer: Dict[Tuple[int, int, str], Dict[int, int]] = field(default_factory=dict) + + init_mpp: dict[str, dict[str, int]] = field( + default_factory=lambda: {"X": {}, "Z": {}} + ) + final_mpp: dict[str, dict[str, int]] = field( + default_factory=lambda: {"X": {}, "Z": {}} + ) + per_layer: dict[tuple[int, int, str], dict[int, int]] = field(default_factory=dict) def record_init_mpp(self, basis: str, label: str, rec: int) -> None: b = basis.upper() @@ -25,7 +29,8 @@ def record_final_mpp(self, basis: str, label: str, rec: int) -> None: b = basis.upper() self.final_mpp[b][label] = int(rec) - def record_layer_meas(self, round_idx: int, layer_idx: int, basis: str, root_q: int, rec: int) -> None: + def record_layer_meas( + self, round_idx: int, layer_idx: int, basis: str, root_q: int, rec: int + ) -> None: key = (int(round_idx), int(layer_idx), basis.upper()) self.per_layer.setdefault(key, {})[int(root_q)] = int(rec) - diff --git a/ACID/src/acid/memory_experiment/registry.py b/ACID/src/acid/memory_experiment/registry.py index 02cadaa..55505ee 100644 --- a/ACID/src/acid/memory_experiment/registry.py +++ b/ACID/src/acid/memory_experiment/registry.py @@ -1,34 +1,33 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Dict, List, Optional from .single_detectors import DetectorInfo @dataclass class DetectorRegistry: - detectors: List[DetectorInfo] = field(default_factory=list) - by_quasi: Dict[str, List[int]] = field(default_factory=dict) - by_product: Dict[str, List[int]] = field(default_factory=dict) + detectors: list[DetectorInfo] = field(default_factory=list) + by_quasi: dict[str, list[int]] = field(default_factory=dict) + by_product: dict[str, list[int]] = field(default_factory=dict) def add(self, info: DetectorInfo) -> None: det_id = info.id self.detectors.append(info) - if info.kind == 'quasi': + if info.kind == "quasi": self.by_quasi.setdefault(info.label, []).append(det_id) - elif info.kind == 'product': + elif info.kind == "product": self.by_product.setdefault(info.label, []).append(det_id) - def get_detector(self, det_id: int) -> Optional[DetectorInfo]: + def get_detector(self, det_id: int) -> DetectorInfo | None: if 0 <= det_id < len(self.detectors): return self.detectors[det_id] return None - def get_detectors_for_quasi(self, label: str) -> List[DetectorInfo]: + def get_detectors_for_quasi(self, label: str) -> list[DetectorInfo]: ids = self.by_quasi.get(label, []) return [self.detectors[i] for i in ids if 0 <= i < len(self.detectors)] - def get_detectors_for_product(self, label: str) -> List[DetectorInfo]: + def get_detectors_for_product(self, label: str) -> list[DetectorInfo]: ids = self.by_product.get(label, []) return [self.detectors[i] for i in ids if 0 <= i < len(self.detectors)] diff --git a/ACID/src/acid/memory_experiment/schedule_index.py b/ACID/src/acid/memory_experiment/schedule_index.py index 93ae874..bb6e620 100644 --- a/ACID/src/acid/memory_experiment/schedule_index.py +++ b/ACID/src/acid/memory_experiment/schedule_index.py @@ -1,28 +1,27 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Dict, List, Optional, Set, Tuple -from acid.scheduling.types import SyndromeExtractionLayer from acid.defects.defective_code import DefectiveCode +from acid.scheduling.types import SyndromeExtractionLayer @dataclass class ScheduleIndex: dcode: DefectiveCode - layers: List[SyndromeExtractionLayer] + layers: list[SyndromeExtractionLayer] def __post_init__(self) -> None: self.L = len(self.layers) # Per-layer measured labels and label->root maps - self.per_layer_labels: List[Set[str]] = [] - self.label_to_root: List[Dict[str, int]] = [] - self.root_to_label: List[Dict[int, str]] = [] + self.per_layer_labels: list[set[str]] = [] + self.label_to_root: list[dict[str, int]] = [] + self.root_to_label: list[dict[int, str]] = [] for Lk in self.layers: - labs = set(stab.label for stab in Lk.chosen.keys()) + labs = {stab.label for stab in Lk.chosen} self.per_layer_labels.append(labs) - lab_to_root: Dict[str, int] = {} - root_to_lab: Dict[int, str] = {} + lab_to_root: dict[str, int] = {} + root_to_lab: dict[int, str] = {} for stab, shed in Lk.chosen.items(): rq = stab.qubit_map[shed.root] lab_to_root[stab.label] = rq @@ -31,33 +30,35 @@ def __post_init__(self) -> None: self.root_to_label.append(root_to_lab) # Quasi basis map - self.basis_of: Dict[str, str] = {} + self.basis_of: dict[str, str] = {} for lab in self.dcode.quasi_labels: # type: ignore[attr-defined] typ, _ = self.dcode.quasi_support(lab) self.basis_of[lab] = typ # Basis label sets for MPP events - self.labels_x: Set[str] = {lab for lab, b in self.basis_of.items() if b == 'X'} - self.labels_z: Set[str] = {lab for lab, b in self.basis_of.items() if b == 'Z'} + self.labels_x: set[str] = {lab for lab, b in self.basis_of.items() if b == "X"} + self.labels_z: set[str] = {lab for lab, b in self.basis_of.items() if b == "Z"} # Contracting layer indices per label (within one schedule period) - self.contracting_ts: Dict[str, List[int]] = {} + self.contracting_ts: dict[str, list[int]] = {} for t, labs in enumerate(self.per_layer_labels): for lab in labs: self.contracting_ts.setdefault(lab, []).append(t) # Anticommutation neighbors G = self.dcode.anticommutation_graph() - self.neighbors: Dict[str, Set[str]] = {} + self.neighbors: dict[str, set[str]] = {} for u, v in G.edges(): self.neighbors.setdefault(u, set()).add(v) self.neighbors.setdefault(v, set()).add(u) - def rounds_for_label(self, lab: str, R: int) -> List[Tuple[int, int]]: + def rounds_for_label(self, lab: str, R: int) -> list[tuple[int, int]]: """Return (r,t) pairs for rounds 1..R where label lab contracts (measured).""" ts = self.contracting_ts.get(lab, []) return [(r, t) for r in range(1, R + 1) for t in ts] - def any_anticomm_measured_between(self, lab: str, A: Tuple[int, int], B: Tuple[int, int]) -> bool: + def any_anticomm_measured_between( + self, lab: str, A: tuple[int, int], B: tuple[int, int] + ) -> bool: """ Return True if any layer strictly between (A,B) measures a quasi that anticommutes with 'lab'. A,B are (round, layer) indices with 1-based round and 0-based layer. @@ -78,7 +79,9 @@ def any_anticomm_measured_between(self, lab: str, A: Tuple[int, int], B: Tuple[i return False # --- Unified anticomm guard across init/final and schedule layers --- - def _event_index(self, kind: str, basis: Optional[str], rt: Optional[Tuple[int, int]], R: int) -> int: + def _event_index( + self, kind: str, basis: str | None, rt: tuple[int, int] | None, R: int + ) -> int: """Map an anchor (kind,basis,rt) to a linear event index. Event order: @@ -88,19 +91,19 @@ def _event_index(self, kind: str, basis: Optional[str], rt: Optional[Tuple[int, 2+R*L: finalX 2+R*L+1: finalZ """ - if kind == 'init': - assert basis in ('X', 'Z') - return 0 if basis == 'X' else 1 - if kind == 'contract': + if kind == "init": + assert basis in ("X", "Z") + return 0 if basis == "X" else 1 + if kind == "contract": assert rt is not None r, t = rt return 2 + (int(r) - 1) * self.L + int(t) - if kind == 'final': - assert basis in ('X', 'Z') - return 2 + R * self.L + (0 if basis == 'X' else 1) + if kind == "final": + assert basis in ("X", "Z") + return 2 + R * self.L + (0 if basis == "X" else 1) raise ValueError(f"Unknown event kind: {kind}") - def _measured_labels_at_event(self, eidx: int, R: int) -> Set[str]: + def _measured_labels_at_event(self, eidx: int, R: int) -> set[str]: if eidx == 0: return self.labels_x if eidx == 1: @@ -122,16 +125,16 @@ def any_anticomm_measured_between_events( *, lab: str, basis: str, - A: Tuple[str, Optional[Tuple[int, int]]], - B: Tuple[str, Optional[Tuple[int, int]]], + A: tuple[str, tuple[int, int] | None], + B: tuple[str, tuple[int, int] | None], R: int, ) -> bool: """ Return True if any anticommuting quasi of 'lab' is measured at any event strictly between anchors A and B (which may be init/final or a contract layer). """ - eA = self._event_index(A[0], basis if A[0] != 'contract' else None, A[1], R) - eB = self._event_index(B[0], basis if B[0] != 'contract' else None, B[1], R) + eA = self._event_index(A[0], basis if A[0] != "contract" else None, A[1], R) + eB = self._event_index(B[0], basis if B[0] != "contract" else None, B[1], R) if eA >= eB: return False nbrs = self.neighbors.get(lab, set()) diff --git a/ACID/src/acid/memory_experiment/single_detectors.py b/ACID/src/acid/memory_experiment/single_detectors.py index 9ccee53..1d6134e 100644 --- a/ACID/src/acid/memory_experiment/single_detectors.py +++ b/ACID/src/acid/memory_experiment/single_detectors.py @@ -1,11 +1,10 @@ from __future__ import annotations from dataclasses import dataclass, field -from typing import Dict, List, Optional, Set, Tuple +from acid.defects.defective_code import DefectiveCode from acid.pauli import PauliString from acid.scheduling.types import SyndromeExtractionLayer -from acid.defects.defective_code import DefectiveCode from .rec_log import MeasurementLog from .schedule_index import ScheduleIndex @@ -14,31 +13,31 @@ @dataclass class DetectorInfo: id: int - kind: str # 'quasi' | 'product' + kind: str # 'quasi' | 'product' label: str - basis: Optional[str] # 'X' | 'Z' for quasi; None for product - start: Dict[str, object] - end: Dict[str, object] - intervening: List[Tuple[int, int]] = field(default_factory=list) - recs: List[int] = field(default_factory=list) + basis: str | None # 'X' | 'Z' for quasi; None for product + start: dict[str, object] + end: dict[str, object] + intervening: list[tuple[int, int]] = field(default_factory=list) + recs: list[int] = field(default_factory=list) @dataclass class DetectorPlan: - rec_sets: List[List[int]] = field(default_factory=list) - infos: List[DetectorInfo] = field(default_factory=list) + rec_sets: list[list[int]] = field(default_factory=list) + infos: list[DetectorInfo] = field(default_factory=list) def plan_quasi_detectors( *, dcode: DefectiveCode, - layers: List[SyndromeExtractionLayer], + layers: list[SyndromeExtractionLayer], sched: ScheduleIndex, log: MeasurementLog, R: int, include_x: bool = True, include_z: bool = True, - filter_labels: Optional[Set[str]] = None, + filter_labels: set[str] | None = None, ) -> DetectorPlan: plan = DetectorPlan() det_id = 0 @@ -46,24 +45,27 @@ def plan_quasi_detectors( n = dcode.base_code.num_qubits for lab in dcode.quasi_labels: # type: ignore[attr-defined] + # don't include if filtered out or basis not included if filter_labels is not None and lab not in filter_labels: continue basis = sched.basis_of[lab] - if (basis == 'X' and not include_x) or (basis == 'Z' and not include_z): + if (basis == "X" and not include_x) or (basis == "Z" and not include_z): continue # Mid-cycle PauliString for this quasi typ, supp = dcode.quasi_support(lab) if typ != basis: typ = basis - Pmid = PauliString.from_supports(supp if basis == 'X' else [], [] if basis == 'X' else supp, n) + Pmid = PauliString.from_supports( + supp if basis == "X" else [], [] if basis == "X" else supp, n + ) # Contracting events across rounds - events: List[Tuple[str, object]] = [] - events.append(('init', None)) + events: list[tuple[str, object]] = [] + events.append(("init", None)) rt_list = sched.rounds_for_label(lab, R) for r, t in rt_list: - events.append(('contract', (r, t))) - events.append(('final', None)) + events.append(("contract", (r, t))) + events.append(("final", None)) for i in range(len(events) - 1): A = events[i] @@ -75,13 +77,13 @@ def plan_quasi_detectors( continue # Sentinel (r,t) to enumerate intervening schedule layers - a_rt: Optional[Tuple[int, int]] = (1, -1) if A[0] == 'init' else A[1] # type: ignore[assignment] - b_rt: Optional[Tuple[int, int]] = (R, L) if B[0] == 'final' else B[1] # type: ignore[assignment] + a_rt: tuple[int, int] | None = (1, -1) if A[0] == "init" else A[1] # type: ignore[assignment] + b_rt: tuple[int, int] | None = (R, L) if B[0] == "final" else B[1] # type: ignore[assignment] # Collect recs - recs: List[int] = [] - intervening: List[Tuple[int, int]] = [] - if A[0] == 'init': + recs: list[int] = [] + intervening: list[tuple[int, int]] = [] + if A[0] == "init": rec_init = log.init_mpp[basis][lab] recs.append(int(rec_init)) @@ -91,12 +93,12 @@ def plan_quasi_detectors( r_i = idx // L + 1 t_i = idx % L Pc = layers[t_i].propagate(Pmid) - if basis == 'X': + if basis == "X": S = set(Pc.x_support()) - key = (r_i, t_i, 'X') + key = (r_i, t_i, "X") else: S = set(Pc.z_support()) - key = (r_i, t_i, 'Z') + key = (r_i, t_i, "Z") root_map = log.per_layer.get(key, {}) for q in S: if q in root_map: @@ -104,12 +106,12 @@ def plan_quasi_detectors( if S: intervening.append((r_i, t_i)) - if B[0] == 'contract': + if B[0] == "contract": r_b, t_b = b_rt # type: ignore[misc] root_q = sched.label_to_root[t_b][lab] rec = log.per_layer[(r_b, t_b, basis)][root_q] recs.append(int(rec)) - elif B[0] == 'final': + elif B[0] == "final": rec = log.final_mpp[basis][lab] recs.append(int(rec)) @@ -119,11 +121,19 @@ def plan_quasi_detectors( plan.rec_sets.append(recs) info = DetectorInfo( id=det_id, - kind='quasi', + kind="quasi", label=lab, basis=basis, - start={'type': A[0], 'round': a_rt[0] if a_rt else None, 'layer': a_rt[1] if a_rt else None}, - end={'type': B[0], 'round': b_rt[0] if b_rt else None, 'layer': b_rt[1] if b_rt else None}, + start={ + "type": A[0], + "round": a_rt[0] if a_rt else None, + "layer": a_rt[1] if a_rt else None, + }, + end={ + "type": B[0], + "round": b_rt[0] if b_rt else None, + "layer": b_rt[1] if b_rt else None, + }, intervening=intervening, recs=list(recs), ) diff --git a/ACID/src/acid/pauli.py b/ACID/src/acid/pauli.py index f7ac638..e41ee86 100644 --- a/ACID/src/acid/pauli.py +++ b/ACID/src/acid/pauli.py @@ -1,21 +1,20 @@ from __future__ import annotations +from collections.abc import Iterable from dataclasses import dataclass -from typing import Iterable, List, Tuple, Dict from acid.gap_distance import compute_nkd_with_gap - -from acid.gf2_utils import gf2_rank, gf2_is_in_span, gf2_left_nullspace +from acid.gf2_utils import gf2_is_in_span, gf2_left_nullspace, gf2_rank @dataclass class PauliString: n: int - X: List[int] - Z: List[int] + X: list[int] + Z: list[int] @staticmethod - def from_supports(Xs: Iterable[int], Zs: Iterable[int], n: int) -> "PauliString": + def from_supports(Xs: Iterable[int], Zs: Iterable[int], n: int) -> PauliString: X = [0] * n Z = [0] * n for q in Xs: @@ -27,7 +26,7 @@ def from_supports(Xs: Iterable[int], Zs: Iterable[int], n: int) -> "PauliString" return PauliString(n=n, X=X, Z=Z) @staticmethod - def from_2n(row: Iterable[int]) -> "PauliString": + def from_2n(row: Iterable[int]) -> PauliString: r = [int(v) & 1 for v in row] assert len(r) % 2 == 0 n = len(r) // 2 @@ -35,38 +34,38 @@ def from_2n(row: Iterable[int]) -> "PauliString": Z = r[n:] return PauliString(n=n, X=X, Z=Z) - def support(self) -> List[int]: + def support(self) -> list[int]: return [i for i, b in enumerate(self.X + self.Z) if b & 1] - - def z_support(self) -> List[int]: + + def z_support(self) -> list[int]: return [i for i, b in enumerate(self.Z) if b & 1] - - def x_support(self) -> List[int]: + + def x_support(self) -> list[int]: return [i for i, b in enumerate(self.X) if b & 1] - def to_2n(self) -> List[int]: + def to_2n(self) -> list[int]: return [int(v) & 1 for v in (self.X + self.Z)] - def to_supports(self) -> Tuple[set[int], set[int]]: + def to_supports(self) -> tuple[set[int], set[int]]: Xs = {i for i, b in enumerate(self.X) if b & 1} Zs = {i for i, b in enumerate(self.Z) if b & 1} return Xs, Zs - def copy(self) -> "PauliString": + def copy(self) -> PauliString: return PauliString(n=self.n, X=self.X[:], Z=self.Z[:]) - def symplectic_dot(self, other: "PauliString") -> int: + def symplectic_dot(self, other: PauliString) -> int: assert self.n == other.n acc = 0 for i in range(self.n): - acc ^= (self.X[i] & other.Z[i]) - acc ^= (self.Z[i] & other.X[i]) + acc ^= self.X[i] & other.Z[i] + acc ^= self.Z[i] & other.X[i] return acc & 1 - def commutes_with(self, other: "PauliString") -> bool: + def commutes_with(self, other: PauliString) -> bool: return self.symplectic_dot(other) == 0 - def multiply(self, other: "PauliString") -> "PauliString": + def multiply(self, other: PauliString) -> PauliString: assert self.n == other.n X = [(a ^ b) & 1 for a, b in zip(self.X, other.X)] Z = [(a ^ b) & 1 for a, b in zip(self.Z, other.Z)] @@ -81,7 +80,7 @@ def conj_cnot(self, control: int, target: int) -> None: if self.Z[target] & 1: self.Z[control] ^= 1 - def conj_steps(self, steps: List[List[Tuple[int, int]]]) -> None: + def conj_steps(self, steps: list[list[tuple[int, int]]]) -> None: for ops in steps: for c, t in ops: self.conj_cnot(c, t) @@ -97,30 +96,36 @@ def __repr__(self) -> str: class CommutingPauliBasis: name: str priority: int - rows: List[PauliString] + rows: list[PauliString] - def as_2n_matrix(self) -> List[List[int]]: + def as_2n_matrix(self) -> list[list[int]]: return [p.to_2n() for p in self.rows] - def count_membership_in(self, S_rows_2n: List[List[int]]) -> Tuple[int, List[int]]: + def count_membership_in(self, S_rows_2n: list[list[int]]) -> tuple[int, list[int]]: # Return (count, indices) where basis.rows[idx] ∈ span(S) - idxs: List[int] = [] + idxs: list[int] = [] for j, p in enumerate(self.rows): if gf2_is_in_span(p.to_2n(), S_rows_2n): idxs.append(j) return len(idxs), idxs @staticmethod - def from_supports(name: str, priority: int, x_supports: List[List[int]], z_supports: List[List[int]], n: int) -> "CommutingPauliBasis": + def from_supports( + name: str, + priority: int, + x_supports: list[list[int]], + z_supports: list[list[int]], + n: int, + ) -> CommutingPauliBasis: # Build PauliStrings then greedily reduce to an independent set - rows: List[PauliString] = [] + rows: list[PauliString] = [] for supp in x_supports: rows.append(PauliString.from_supports(supp, [], n)) for supp in z_supports: rows.append(PauliString.from_supports([], supp, n)) # Independent reduction - acc: List[List[int]] = [] - keep: List[PauliString] = [] + acc: list[list[int]] = [] + keep: list[PauliString] = [] r = 0 for p in rows: row = p.to_2n() @@ -134,13 +139,13 @@ def from_supports(name: str, priority: int, x_supports: List[List[int]], z_suppo @dataclass class AntiCommutingPauliBasis: name: str - X_rows: List[PauliString] - Z_rows: List[PauliString] + X_rows: list[PauliString] + Z_rows: list[PauliString] - def stacked_2n(self) -> List[List[int]]: + def stacked_2n(self) -> list[list[int]]: return [p.to_2n() for p in (self.X_rows + self.Z_rows)] - def describe_intersection_with(self, S_rows_2n: List[List[int]]) -> List[str]: + def describe_intersection_with(self, S_rows_2n: list[list[int]]) -> list[str]: # Left nullspace trick on M = [B; S], where B = [X_rows; Z_rows] B = self.stacked_2n() if not B: @@ -149,10 +154,10 @@ def describe_intersection_with(self, S_rows_2n: List[List[int]]) -> List[str]: L = gf2_left_nullspace(M) if not L: return [] - desc: List[str] = [] + desc: list[str] = [] p = len(B) kx = len(self.X_rows) - Y_acc: List[List[int]] = [] + Y_acc: list[list[int]] = [] for w in L: if len(w) != len(M): continue @@ -167,38 +172,52 @@ def describe_intersection_with(self, S_rows_2n: List[List[int]]) -> List[str]: if gf2_rank(Y_acc + [yi]) == gf2_rank(Y_acc): continue Y_acc.append(yi) - parts: List[str] = [] + parts: list[str] = [] for j in range(kx): if x[j] & 1: - parts.append(f"X{j+1}") + parts.append(f"X{j + 1}") for j in range(len(self.Z_rows)): if x[kx + j] & 1: - parts.append(f"Z{j+1}") + parts.append(f"Z{j + 1}") desc.append("".join(parts) if parts else "1") return desc # CSS/Stabiliser code containers and helpers + @dataclass class StabiliserCode: num_qubits: int - row_labels: List[str] - Hx: List[List[int]] - Hz: List[List[int]] + row_labels: list[str] + Hx: list[list[int]] + Hz: list[list[int]] def __len__(self) -> int: return len(self.row_labels) @property - def symplectic(self) -> List[List[int]]: + def symplectic(self) -> list[list[int]]: return [hx_row + hz_row for hx_row, hz_row in zip(self.Hx, self.Hz)] - def nkd_via_gap(self, *, gap_exe: str = "gap", trials: int = 1000, mindist: int = 0, debug: int = 1, timeout: int = 300) -> tuple[int, int, int]: - n, k, d = compute_nkd_with_gap(self.Hx, self.Hz, gap_exe=gap_exe, trials=trials, mindist=mindist, debug=debug, timeout=timeout) + def nkd_via_gap( + self, + *, + gap_exe: str = "gap", + trials: int = 1000, + mindist: int = 0, + debug: int = 1, + timeout: int = 300, + ) -> tuple[int, int, int]: + n, k, d = compute_nkd_with_gap( + self.Hx, + self.Hz, + gap_exe=gap_exe, + trials=trials, + mindist=mindist, + debug=debug, + timeout=timeout, + ) return n, k, d - - # Future: add gauges if desired as another AntiCommutingPauliBasis - diff --git a/ACID/src/acid/scheduling/__init__.py b/ACID/src/acid/scheduling/__init__.py index 5c5ab16..9dba3a6 100644 --- a/ACID/src/acid/scheduling/__init__.py +++ b/ACID/src/acid/scheduling/__init__.py @@ -1,2 +1 @@ """Scheduling templates and typed constructs used by the solver.""" - diff --git a/ACID/src/acid/scheduling/enumeration.py b/ACID/src/acid/scheduling/enumeration.py index 9c5517f..089bd5e 100644 --- a/ACID/src/acid/scheduling/enumeration.py +++ b/ACID/src/acid/scheduling/enumeration.py @@ -2,18 +2,21 @@ Schedules are lists of directed moves per timestep that gather onto the root. """ -from typing import Hashable, Iterable, List, Tuple, Dict + import itertools as it +from collections import namedtuple +from collections.abc import Hashable, Iterable + import networkx as nx from networkx.algorithms.tree.mst import SpanningTreeIterator -from collections import namedtuple # A Schedule is: {"root": node, "steps": List[List[Tuple[u,v]]]} # where steps[t] is the list of directed edges executed at timestep t. Schedule = namedtuple("Schedule", ["root", "steps"]) -def enumerate_all_schedules(G: nx.Graph, max_steps: int) -> Iterable[Dict[str, object]]: + +def enumerate_all_schedules(G: nx.Graph, max_steps: int) -> Iterable[dict[str, object]]: """ Enumerate every valid gather schedule for each spanning tree of G and each root, subject to a horizon of `max_steps`. Each yielded item is: @@ -36,18 +39,20 @@ def enumerate_all_schedules(G: nx.Graph, max_steps: int) -> Iterable[Dict[str, o continue # Enumerate schedules that gather to `root` within max_steps. - for steps in _gather_subtree_schedules(adj, height, root, parent=None, max_steps_left=max_steps): + for steps in _gather_subtree_schedules( + adj, height, root, parent=None, max_steps_left=max_steps + ): yield Schedule(root, steps) def _compute_subtree_heights( - adj: Dict[Hashable, Dict[Hashable, dict]], root: Hashable -) -> Dict[Hashable, int]: + adj: dict[Hashable, dict[Hashable, dict]], root: Hashable +) -> dict[Hashable, int]: """ Return subtree heights for a fixed root: height[u] = max distance from u to any descendant (leaf has height 0). Uses post-order DFS rooted at `root`. """ - height: Dict[Hashable, int] = {} + height: dict[Hashable, int] = {} def dfs(u: Hashable, parent: Hashable) -> int: h = 0 @@ -63,12 +68,12 @@ def dfs(u: Hashable, parent: Hashable) -> int: def _gather_subtree_schedules( - adj: Dict[Hashable, Dict[Hashable, dict]], - height: Dict[Hashable, int], + adj: dict[Hashable, dict[Hashable, dict]], + height: dict[Hashable, int], u: Hashable, parent: Hashable, max_steps_left: int, -) -> Iterable[List[List[Tuple[Hashable, Hashable]]]]: +) -> Iterable[list[list[tuple[Hashable, Hashable]]]]: """ Enumerate schedules that gather all tokens in the subtree rooted at `u` (w.r.t. the chosen global root) *to u* within `max_steps_left` steps. diff --git a/ACID/src/acid/scheduling/template_factory.py b/ACID/src/acid/scheduling/template_factory.py index 5bc2359..25ecb6e 100644 --- a/ACID/src/acid/scheduling/template_factory.py +++ b/ACID/src/acid/scheduling/template_factory.py @@ -1,7 +1,8 @@ from __future__ import annotations + """Per-build deduplication of StabiliserTemplate instances.""" -from typing import List, Set, Tuple, Optional + import networkx as nx from .types import StabiliserTemplate @@ -15,28 +16,41 @@ class TemplateFactory: """ def __init__(self) -> None: - self._cache: dict[Tuple, StabiliserTemplate] = {} + self._cache: dict[tuple, StabiliserTemplate] = {} @staticmethod - def _key(pauli_type: str, n_qubits: int, connectivity_subgraph: nx.Graph, SEC_cycle_length: int) -> Tuple: - edges = tuple(sorted((min(u, v), max(u, v)) - for (u, v) in connectivity_subgraph.edges())) + def _key( + pauli_type: str, + n_qubits: int, + connectivity_subgraph: nx.Graph, + SEC_cycle_length: int, + ) -> tuple: + edges = tuple( + sorted((min(u, v), max(u, v)) for (u, v) in connectivity_subgraph.edges()) + ) return (pauli_type, int(n_qubits), int(SEC_cycle_length), edges) - def get_or_create(self, pauli_type: str, n_qubits: int, - connectivity_subgraph: nx.Graph, SEC_cycle_length: int, - name: str = "", - preferred_roots: Optional[List[int]] = None, - preferred_edges: Optional[dict[Tuple[int, int], Optional[List[int]]]] = None, - schedule_hint: List[List[Tuple[int, int]]] | None = None, - layer_hint: int | None = None) -> StabiliserTemplate: - k = self._key(pauli_type, n_qubits, - connectivity_subgraph, SEC_cycle_length) + def get_or_create( + self, + pauli_type: str, + n_qubits: int, + connectivity_subgraph: nx.Graph, + SEC_cycle_length: int, + name: str = "", + preferred_roots: list[int] | None = None, + preferred_edges: dict[tuple[int, int], list[int] | None] | None = None, + schedule_hint: list[list[tuple[int, int]]] | None = None, + layer_hint: int | None = None, + ) -> StabiliserTemplate: + k = self._key(pauli_type, n_qubits, connectivity_subgraph, SEC_cycle_length) obj = self._cache.get(k) if obj is not None: return obj obj = StabiliserTemplate( - pauli_type, n_qubits, connectivity_subgraph, SEC_cycle_length, + pauli_type, + n_qubits, + connectivity_subgraph, + SEC_cycle_length, name=name, preferred_roots=preferred_roots, preferred_edges=preferred_edges, diff --git a/ACID/src/acid/scheduling/types.py b/ACID/src/acid/scheduling/types.py index e2f81e3..2984675 100644 --- a/ACID/src/acid/scheduling/types.py +++ b/ACID/src/acid/scheduling/types.py @@ -1,10 +1,9 @@ from __future__ import annotations + """Core scheduling types: templates, schedules, and layer selection.""" -from dataclasses import dataclass import itertools -from typing import List, Tuple, Set, Optional, Dict -import numpy as np +from dataclasses import dataclass from networkx import DiGraph, Graph @@ -13,9 +12,15 @@ class Stabiliser: """A placed stabiliser instance built from a template and a qubit map.""" - def __init__(self, stabiliser_template: "StabiliserTemplate", qubit_map: List[int], label: str): + + def __init__( + self, + stabiliser_template: StabiliserTemplate, + qubit_map: list[int], + label: str, + ): self.stabiliser_template = stabiliser_template - self.qubit_map: List[int] = list(qubit_map) + self.qubit_map: list[int] = list(qubit_map) self.qubit_map_reverse = {q: i for i, q in enumerate(qubit_map)} self.label = label @@ -28,7 +33,7 @@ def connectivity_subgraph(self) -> Graph: return self.stabiliser_template.connectivity_subgraph @property - def qubit_set(self) -> Set[int]: + def qubit_set(self) -> set[int]: return set(self.qubit_map) @@ -37,7 +42,15 @@ class StabiliserSchedule: Stores per-timestep directed ops and derived Pauli frames for compatibility. """ - def __init__(self, shed_id: int, schedule_length: int, root: int, raw_ops: List[List[Tuple[int, int]]], stabiliser_template: "StabiliserTemplate"): + + def __init__( + self, + shed_id: int, + schedule_length: int, + root: int, + raw_ops: list[list[tuple[int, int]]], + stabiliser_template: StabiliserTemplate, + ): assert len(raw_ops) == schedule_length self.id = shed_id self.length = schedule_length @@ -48,79 +61,141 @@ def __init__(self, shed_id: int, schedule_length: int, root: int, raw_ops: List[ self.pauli_frames = self.calculate_pauli_prop(raw_ops) self.preferred: bool = False - if self.pauli_type == 'X': + if self.pauli_type == "X": self.ops = raw_ops - self.reversed_ops = [[(b, a) for (a, b) in step] - for step in raw_ops] + self.reversed_ops = [[(b, a) for (a, b) in step] for step in raw_ops] else: self.ops = [[(b, a) for (a, b) in step] for step in raw_ops] self.reversed_ops = raw_ops def calculate_pauli_prop(self, raw_ops): - pauli_frames = [[1]*self.n_qubits] + pauli_frames = [[1] * self.n_qubits] for i, ops in enumerate(raw_ops): pauli_frames.append(pauli_frames[i].copy()) - for (a, b) in ops: - pauli_frames[i+1][a] = pauli_frames[i][a] ^ pauli_frames[i][b] + for a, b in ops: + pauli_frames[i + 1][a] = pauli_frames[i][a] ^ pauli_frames[i][b] assert pauli_frames[self.length] == [ - (1 if q_i == self.root else 0) for q_i in range(self.n_qubits)] + (1 if q_i == self.root else 0) for q_i in range(self.n_qubits) + ] return pauli_frames[:-1] - def compatible(self, other: "StabiliserSchedule", common_qubits: dict) -> bool: - common_qubits_reverse = {v: k for k, v in common_qubits.items()} - common_qubits_1 = set(common_qubits.keys()) - common_qubits_2 = set(common_qubits.values()) - if self.root in common_qubits_1 and other.root in common_qubits_2: - if common_qubits[self.root] == other.root: + def compatible(self, other: StabiliserSchedule, self_to_other_qubits: dict) -> bool: + # Map local-overlap indices in both directions between the two schedules. + other_to_self_qubits = {v: k for k, v in self_to_other_qubits.items()} + shared_qubits_in_self = set(self_to_other_qubits.keys()) + shared_qubits_in_other = set(self_to_other_qubits.values()) + + # If both roots land on the same physical qubit, they cannot coexist. + if self.root in shared_qubits_in_self and other.root in shared_qubits_in_other: + if self_to_other_qubits[self.root] == other.root: return False - ops_1_standard = self.ops if other.pauli_type == 'X' else self.reversed_ops - ops_2_standard = other.ops if self.pauli_type == 'X' else other.reversed_ops + + # Put both schedules into a shared orientation so edge comparisons are meaningful + # across X/Z templates. + ops_1_standard = self.ops if other.pauli_type == "X" else self.reversed_ops + ops_2_standard = other.ops if self.pauli_type == "X" else other.reversed_ops + + # Keep only operations touching overlap qubits, timestep by timestep. filtered_ops_1 = [] filtered_ops_2 = [] for ops_1, ops_2 in zip(ops_1_standard, ops_2_standard): filtered_ops_1.append( - [(a, b) for (a, b) in ops_1 if a in common_qubits_1 or b in common_qubits_1]) + [ + (a, b) + for (a, b) in ops_1 + if a in shared_qubits_in_self or b in shared_qubits_in_self + ] + ) filtered_ops_2.append( - [(a, b) for (a, b) in ops_2 if a in common_qubits_2 or b in common_qubits_2]) - filtered_op_qubits_1 = set(common_qubits[q] for q in itertools.chain( - *filtered_ops_1[-1]) if q in common_qubits_1) + [ + (a, b) + for (a, b) in ops_2 + if a in shared_qubits_in_other or b in shared_qubits_in_other + ] + ) + + # Overlap qubits used by schedule-1 at this timestep, represented + # in schedule-2 indexing for direct clash detection. + filtered_op_qubits_1 = { + self_to_other_qubits[q] + for q in itertools.chain(*filtered_ops_1[-1]) + if q in shared_qubits_in_self + } + + # Reject simultaneous use of an overlap qubit unless the pair is the + # same mapped edge (accounting for opposite Pauli orientation). for a2, b2 in filtered_ops_2[-1]: - if a2 in common_qubits_2 and b2 in common_qubits_2: - a_flip_2, b_flip_2 = (a2, b2) if self.pauli_type == other.pauli_type else (b2, a2) - if (common_qubits_reverse[a_flip_2], common_qubits_reverse[b_flip_2]) in filtered_ops_1[-1]: + if a2 in shared_qubits_in_other and b2 in shared_qubits_in_other: + a_flip_2, b_flip_2 = ( + (a2, b2) if self.pauli_type == other.pauli_type else (b2, a2) + ) + if ( + other_to_self_qubits[a_flip_2], + other_to_self_qubits[b_flip_2], + ) in filtered_ops_1[-1]: continue if a2 in filtered_op_qubits_1 or b2 in filtered_op_qubits_1: return False + + # Pauli-frame compatibility checks across each timestep. pf_1 = self.pauli_frames pf_2 = other.pauli_frames - for ops_1, ops_2, pf_1_t, pf_2_t in zip(filtered_ops_1, filtered_ops_2, pf_1, pf_2): + for ops_1, ops_2, pf_1_t, pf_2_t in zip( + filtered_ops_1, filtered_ops_2, pf_1, pf_2 + ): + # Validate schedule-1 ops against schedule-2 frame state. for a1, b1 in ops_1: - if a1 in common_qubits_1 and b1 in common_qubits_1: - a_flip_1, b_flip_1 = (a1, b1) if self.pauli_type == other.pauli_type else (b1, a1) - if (common_qubits[a_flip_1], common_qubits[b_flip_1]) in ops_2: + if a1 in shared_qubits_in_self and b1 in shared_qubits_in_self: + a_flip_1, b_flip_1 = ( + (a1, b1) if self.pauli_type == other.pauli_type else (b1, a1) + ) + if ( + self_to_other_qubits[a_flip_1], + self_to_other_qubits[b_flip_1], + ) in ops_2: continue - if b1 in common_qubits_1 and pf_2_t[common_qubits[b1]] == 1: + if ( + b1 in shared_qubits_in_self + and pf_2_t[self_to_other_qubits[b1]] == 1 + ): return False + + # Validate schedule-2 ops against schedule-1 frame state. for a2, b2 in ops_2: - if a2 in common_qubits_2 and b2 in common_qubits_2: - a_flip_2, b_flip_2 = (a2, b2) if self.pauli_type == other.pauli_type else (b2, a2) - if (common_qubits_reverse[a_flip_2], common_qubits_reverse[b_flip_2]) in ops_1: + if a2 in shared_qubits_in_other and b2 in shared_qubits_in_other: + a_flip_2, b_flip_2 = ( + (a2, b2) if self.pauli_type == other.pauli_type else (b2, a2) + ) + if ( + other_to_self_qubits[a_flip_2], + other_to_self_qubits[b_flip_2], + ) in ops_1: continue - if b2 in common_qubits_2 and pf_1_t[common_qubits_reverse[b2]] == 1: + if ( + b2 in shared_qubits_in_other + and pf_1_t[other_to_self_qubits[b2]] == 1 + ): return False + + # No shared-qubit or frame conflicts found. return True class StabiliserTemplate: next_id = 0 - def __init__(self, pauli_type: str, - n_qubits: int, connectivity_subgraph: Graph, - SEC_cycle_length: int, name: str = "", - preferred_roots: List[int] = None, - preferred_edges: dict[Tuple[int, int], Optional[List[int]]] | None = None, - schedule_hint: List[List[Tuple[int, int]]] | None = None, - layer_hint: int | None = None): + def __init__( + self, + pauli_type: str, + n_qubits: int, + connectivity_subgraph: Graph, + SEC_cycle_length: int, + name: str = "", + preferred_roots: list[int] | None = None, + preferred_edges: dict[tuple[int, int], list[int] | None] | None = None, + schedule_hint: list[list[tuple[int, int]]] | None = None, + layer_hint: int | None = None, + ): self.template_id = StabiliserTemplate.next_id StabiliserTemplate.next_id += 1 self.n_qubits = n_qubits @@ -136,57 +211,89 @@ def __init__(self, pauli_type: str, self.schedule_hint_index = self.find_schedule_hint_index(schedule_hint) self.layer_hint = layer_hint if (self.schedule_hint_index is None) != (self.layer_hint is None): - raise ValueError("Both schedule_hint and layer_hint must be provided together.") + raise ValueError( + "Both schedule_hint and layer_hint must be provided together." + ) def make_schedules(self, SEC_cycle_length: int): schedules = [] import os + verbose_enum = os.environ.get("FAB_SCHEDULE_ENUM_VERBOSE", "0") == "1" if verbose_enum: try: from tqdm import tqdm # type: ignore - iter_src = list(enumerate_all_schedules(self.connectivity_subgraph, SEC_cycle_length)) + + iter_src = list( + enumerate_all_schedules( + self.connectivity_subgraph, SEC_cycle_length + ) + ) iterator = enumerate(iter_src) - pbar = tqdm(total=len(iter_src), desc=f"[enum] {self.name or 'tmpl'}", leave=False) + pbar = tqdm( + total=len(iter_src), + desc=f"[enum] {self.name or 'tmpl'}", + leave=False, + ) use_pbar = True except Exception: - iterator = enumerate(enumerate_all_schedules(self.connectivity_subgraph, SEC_cycle_length)) + iterator = enumerate( + enumerate_all_schedules( + self.connectivity_subgraph, SEC_cycle_length + ) + ) pbar = None use_pbar = False else: - iterator = enumerate(enumerate_all_schedules(self.connectivity_subgraph, SEC_cycle_length)) + iterator = enumerate( + enumerate_all_schedules(self.connectivity_subgraph, SEC_cycle_length) + ) pbar = None use_pbar = False for i, schedule in iterator: - sched = StabiliserSchedule(i, SEC_cycle_length, schedule.root, schedule.steps, self) + sched = StabiliserSchedule( + i, SEC_cycle_length, schedule.root, schedule.steps, self + ) # Mark preferred according to preferred_roots/edges rules # If no preferences are provided (both preferred_roots is None and preferred_edges empty/None), # then no schedules are preferred. - has_any_pref = (self.preferred_roots is not None) or bool(self.preferred_edges) - root_ok = True if self.preferred_roots is None else (sched.root in self.preferred_roots) + has_any_pref = (self.preferred_roots is not None) or bool( + self.preferred_edges + ) + root_ok = ( + True + if self.preferred_roots is None + else (sched.root in self.preferred_roots) + ) edges_ok = True time_ok = True if self.preferred_edges: # Build used edge -> timestep map (undirected local edge indices) - used: dict[Tuple[int, int], int] = {} + used: dict[tuple[int, int], int] = {} for t, ops in enumerate(sched.ops): for a, b in ops: e = (a, b) if a <= b else (b, a) used[e] = t - pref_keys = set((u, v) if u <= v else (v, u) for (u, v) in self.preferred_edges.keys()) + pref_keys = { + (u, v) if u <= v else (v, u) for (u, v) in self.preferred_edges + } used_keys = set(used.keys()) # Only allowed edges may be used if not used_keys.issubset(pref_keys): edges_ok = False # For edges with time constraints, require usage at allowed times if edges_ok: - for (e_raw, times) in self.preferred_edges.items(): - e = (e_raw[0], e_raw[1]) if e_raw[0] <= e_raw[1] else (e_raw[1], e_raw[0]) + for e_raw, times in self.preferred_edges.items(): + e = ( + (e_raw[0], e_raw[1]) + if e_raw[0] <= e_raw[1] + else (e_raw[1], e_raw[0]) + ) if times is not None: # Must be used and at an allowed timestep t_used = used.get(e, None) - if t_used is None or t_used not in set(int(x) for x in times): + if t_used is None or t_used not in {int(x) for x in times}: time_ok = False break sched.preferred = bool(has_any_pref and root_ok and edges_ok and time_ok) @@ -197,20 +304,25 @@ def make_schedules(self, SEC_cycle_length: int): pbar.close() if len(schedules) == 0: raise ValueError( - f"No valid schedules found for stabiliser template {self.name}") + f"No valid schedules found for stabiliser template {self.name}" + ) return schedules - def make_stabiliser(self, qubits: List[int], label: str) -> "Stabiliser": + def make_stabiliser(self, qubits: list[int], label: str) -> Stabiliser: return Stabiliser(self, qubits, label) - - def find_schedule_hint_index(self, schedule_hint: List[List[Tuple[int, int]]] | None) -> Optional[int]: + + def find_schedule_hint_index( + self, schedule_hint: list[list[tuple[int, int]]] | None + ) -> int | None: if schedule_hint is None: return None default_schedule_sorted = [sorted(step) for step in schedule_hint] for i, schedule in enumerate(self.schedules): if default_schedule_sorted == [sorted(step) for step in schedule.ops]: return i - raise ValueError("Provided schedule_hint does not match any enumerated schedule.") + raise ValueError( + "Provided schedule_hint does not match any enumerated schedule." + ) def __hash__(self): return self.template_id @@ -223,23 +335,35 @@ class SyndromeExtractionLayer: def __post_init__(self): self.cycle_length = next(iter(self.chosen.items()))[1].length - for _, schedule in self.chosen.items(): - assert schedule.length == self.cycle_length, "All schedules in a syndrome extraction layer must have the same length" - - self.x_roots = set(s.qubit_map[shed.root] for s, shed in self.chosen.items( - ) if s.stabiliser_template.pauli_type == 'X') - self.z_roots = set(s.qubit_map[shed.root] for s, shed in self.chosen.items( - ) if s.stabiliser_template.pauli_type == 'Z') - - def collect_CNOTS(self) -> List[List[Tuple[int, int]]]: - all_CNOTS: List[Set[Tuple[int, int]]] = [ - set() for _ in range(self.cycle_length)] + for schedule in self.chosen.values(): + assert schedule.length == self.cycle_length, ( + "All schedules in a syndrome extraction layer must have the same length" + ) + + self.x_roots = { + s.qubit_map[shed.root] + for s, shed in self.chosen.items() + if s.stabiliser_template.pauli_type == "X" + } + self.z_roots = { + s.qubit_map[shed.root] + for s, shed in self.chosen.items() + if s.stabiliser_template.pauli_type == "Z" + } + + def collect_CNOTS(self) -> list[list[tuple[int, int]]]: + all_CNOTS: list[set[tuple[int, int]]] = [ + set() for _ in range(self.cycle_length) + ] for t in range(self.cycle_length): used_qubits = set() for stab, schedule in self.chosen.items(): for a, b in schedule.ops[t]: control, target = stab.qubit_map[b], stab.qubit_map[a] - if (target in used_qubits or control in used_qubits) and (control, target) not in all_CNOTS[t]: + if (target in used_qubits or control in used_qubits) and ( + control, + target, + ) not in all_CNOTS[t]: raise ValueError("Invalid schedule. Clashing qubits.") all_CNOTS[t].add((control, target)) used_qubits.add(target) @@ -256,11 +380,13 @@ def is_compatible_with_scheduling_graph(self, scheduling_graph: DiGraph) -> bool if u in self.chosen and v in self.chosen: data = scheduling_graph.get_edge_data(u, v) pair = (self.chosen[u].id, self.chosen[v].id) - if pair not in data['allowed_pairs']: + if pair not in data["allowed_pairs"]: return False return True - def endcycle_expanded_stabilisers(self) -> tuple[list[list[int]], list[list[int]], list[int]]: + def endcycle_expanded_stabilisers( + self, + ) -> tuple[list[list[int]], list[list[int]], list[int]]: if self.code is None: raise ValueError("SyndromeExtractionLayer has no associated code") steps = self.collect_CNOTS() @@ -275,7 +401,7 @@ def endcycle_expanded_stabilisers(self) -> tuple[list[list[int]], list[list[int] if stab in chosen_set: continue support = set(stab.qubit_map) - if stab.pauli_type == 'X': + if stab.pauli_type == "X": for ops in steps: for control, target in ops: if control in support: @@ -293,8 +419,9 @@ def endcycle_expanded_stabilisers(self) -> tuple[list[list[int]], list[list[int] else: support.add(control) z_rows.append(sorted(support)) - kept_qubits = [q for q in range( - self.code.num_qubits) if q not in excluded_roots] + kept_qubits = [ + q for q in range(self.code.num_qubits) if q not in excluded_roots + ] return x_rows, z_rows, kept_qubits def endcycle_parity_check_matrix(self) -> dict: @@ -303,7 +430,7 @@ def endcycle_parity_check_matrix(self) -> dict: n_eff = len(kept_qubits) Hx = [[0] * n_eff for _ in range(len(x_rows))] Hz = [[0] * n_eff for _ in range(len(z_rows))] - labels: List[str] = [] + labels: list[str] = [] for i, supp in enumerate(x_rows): labels.append(f"X_row_{i}") for q in supp: @@ -317,11 +444,11 @@ def endcycle_parity_check_matrix(self) -> dict: if j is not None: Hz[k][j] ^= 1 from acid.pauli import StabiliserCode + return StabiliserCode(num_qubits=n_eff, row_labels=labels, Hx=Hx, Hz=Hz) + def propagate(self, P: PauliString) -> PauliString: - def propagate(self, P: "PauliString") -> "PauliString": - from acid.pauli import PauliString if P.n != self.code.num_qubits: raise ValueError("PauliString has wrong length for this code") Q = P.copy() @@ -329,44 +456,44 @@ def propagate(self, P: "PauliString") -> "PauliString": Q.conj_steps(steps) return Q - def collect_cx_stim(self) -> List[List[Tuple[int, int]]]: + def collect_cx_stim(self) -> list[list[tuple[int, int]]]: return self.collect_CNOTS() @staticmethod - def cx_line_stim(step: List[Tuple[int, int]]) -> str: + def cx_line_stim(step: list[tuple[int, int]]) -> str: if not step: - return '' - flat: List[str] = [] + return "" + flat: list[str] = [] for c, t in step: flat.append(str(c)) flat.append(str(t)) - return 'CX ' + ' '.join(flat) + return "CX " + " ".join(flat) - def emit_layer_contract(self) -> List[str]: - lines: List[str] = [] + def emit_layer_contract(self) -> list[str]: + lines: list[str] = [] for step in self.collect_cx_stim(): s = self.cx_line_stim(step) if s: lines.append(s) - lines.append('TICK') + lines.append("TICK") return lines - def emit_layer_expand(self) -> List[str]: - lines: List[str] = [] + def emit_layer_expand(self) -> list[str]: + lines: list[str] = [] steps = self.collect_cx_stim() for step in reversed(steps): s = self.cx_line_stim(step) if s: lines.append(s) - lines.append('TICK') + lines.append("TICK") return lines - def roots_by_basis(self) -> Tuple[List[int], List[int]]: - x_roots: List[int] = [] - z_roots: List[int] = [] + def roots_by_basis(self) -> tuple[list[int], list[int]]: + x_roots: list[int] = [] + z_roots: list[int] = [] for stab, shed in self.chosen.items(): root_q = stab.qubit_map[shed.root] - if stab.pauli_type == 'X': + if stab.pauli_type == "X": x_roots.append(root_q) else: z_roots.append(root_q) diff --git a/ACID/src/acid/solver/__init__.py b/ACID/src/acid/solver/__init__.py index 2c5748c..48a483f 100644 --- a/ACID/src/acid/solver/__init__.py +++ b/ACID/src/acid/solver/__init__.py @@ -1,2 +1 @@ """Solvers for layered scheduling and pruning utilities.""" - diff --git a/ACID/src/acid/solver/prune.py b/ACID/src/acid/solver/prune.py index 92ad6d8..7e9daf1 100644 --- a/ACID/src/acid/solver/prune.py +++ b/ACID/src/acid/solver/prune.py @@ -1,26 +1,30 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Dict, List, Set, Tuple import networkx as nx @dataclass class PruningResult: - allowed_per_label: Dict[str, Set[int]] + allowed_per_label: dict[str, set[int]] filtered_graph: nx.DiGraph - stats: Dict[str, object] + stats: dict[str, object] -def _summary(nums: List[int]) -> Dict[str, float]: +def _summary(nums: list[int]) -> dict[str, float]: if not nums: return {"min": 0.0, "max": 0.0, "median": 0.0, "mean": 0.0} a = sorted(nums) n = len(a) mid = a[n // 2] if (n % 2) == 1 else (0.5 * (a[n // 2 - 1] + a[n // 2])) s = sum(a) - return {"min": float(a[0]), "max": float(a[-1]), "median": float(mid), "mean": float(s) / float(n)} + return { + "min": float(a[0]), + "max": float(a[-1]), + "median": float(mid), + "mean": float(s) / float(n), + } def prune_schedule_graph( @@ -35,8 +39,8 @@ def prune_schedule_graph( raise TypeError("scheduling_graph must be a networkx.DiGraph") # Stabiliser labels and schedule counts - labels: List[str] = [] - K_by_label: Dict[str, int] = {} + labels: list[str] = [] + K_by_label: dict[str, int] = {} for stab in scheduling_graph.nodes(): lab = getattr(stab, "label", None) if not isinstance(lab, str) or not lab: @@ -53,22 +57,28 @@ def prune_schedule_graph( K_by_label[lab] = K # Preferred ids per label - preferred_ids: Dict[str, Set[int]] = {} + preferred_ids: dict[str, set[int]] = {} for stab in scheduling_graph.nodes(): - lab = getattr(stab, "label") - tmpl = getattr(stab, "stabiliser_template") - pref = set(i for i, sch in enumerate(tmpl.schedules) if getattr(sch, "preferred", False)) + lab = stab.label + tmpl = stab.stabiliser_template + pref = { + i + for i, sch in enumerate(tmpl.schedules) + if getattr(sch, "preferred", False) + } preferred_ids[lab] = pref # Keep sets per label - kept: Dict[str, Set[int]] = {lab: set() for lab in labels} + kept: dict[str, set[int]] = {lab: set() for lab in labels} preferred_total = 0 for lab in labels: K = K_by_label[lab] target = min(M, K) pref = preferred_ids.get(lab, set()) if len(pref) > target: - raise RuntimeError(f"Preferred schedules ({len(pref)}) exceed M={target} for stabiliser {lab}") + raise RuntimeError( + f"Preferred schedules ({len(pref)}) exceed M={target} for stabiliser {lab}" + ) if K <= target: kept[lab] = set(range(K)) else: @@ -76,30 +86,38 @@ def prune_schedule_graph( preferred_total += len(pref) if preferred_total == 0 and verbose: - print("[prune] warning: no preferred schedules marked across the schedule graph") + print( + "[prune] warning: no preferred schedules marked across the schedule graph" + ) # Precompute neighbor compatibility maps for scoring from collections import defaultdict - map_out: Dict[object, Dict[str, Dict[int, Set[int]]]] = {} - map_in: Dict[object, Dict[str, Dict[int, Set[int]]]] = {} - node_by_label: Dict[str, object] = {getattr(stab, "label"): stab for stab in scheduling_graph.nodes()} + map_out: dict[object, dict[str, dict[int, set[int]]]] = {} + map_in: dict[object, dict[str, dict[int, set[int]]]] = {} + + node_by_label: dict[str, object] = { + stab.label: stab for stab in scheduling_graph.nodes() + } it_edges = scheduling_graph.edges(data=True) if verbose: try: from tqdm import tqdm # type: ignore - it_edges = tqdm(list(it_edges), desc="[prune] build compat maps", leave=False) + + it_edges = tqdm( + list(it_edges), desc="[prune] build compat maps", leave=False + ) except Exception: pass for u, v, data in it_edges: allowed = set(data.get("allowed_pairs") or []) u_map = map_out.setdefault(u, {}) - mout = u_map.setdefault(getattr(v, "label"), defaultdict(set)) - for (ku, kv) in allowed: + mout = u_map.setdefault(v.label, defaultdict(set)) + for ku, kv in allowed: mout[int(ku)].add(int(kv)) v_map_in = map_in.setdefault(v, {}) - minv = v_map_in.setdefault(getattr(u, "label"), defaultdict(set)) - for (ku, kv) in allowed: + minv = v_map_in.setdefault(u.label, defaultdict(set)) + for ku, kv in allowed: minv[int(kv)].add(int(ku)) # Scoring and fill for labels where K > M @@ -107,6 +125,7 @@ def prune_schedule_graph( if verbose: try: from tqdm import tqdm # type: ignore + it_labels = list(it_labels) it_labels = tqdm(it_labels, desc="[prune] score+fill labels", leave=False) except Exception: @@ -123,15 +142,15 @@ def prune_schedule_graph( in_by_label = map_in.get(u_node, {}) # Neighbor preferred sets - neigh_pref: Dict[str, Set[int]] = {} + neigh_pref: dict[str, set[int]] = {} for _, v, _ in scheduling_graph.out_edges(u_node, data=True): - v_lab = getattr(v, "label") + v_lab = v.label neigh_pref[v_lab] = preferred_ids.get(v_lab, set()) for w, _, _ in scheduling_graph.in_edges(u_node, data=True): - w_lab = getattr(w, "label") + w_lab = w.label neigh_pref[w_lab] = preferred_ids.get(w_lab, set()) - scored: List[Tuple[int, int, int]] = [] + scored: list[tuple[int, int, int]] = [] for i in candidates: primary = 0 tieb = 0 @@ -156,19 +175,23 @@ def prune_schedule_graph( G2.add_nodes_from(scheduling_graph.nodes()) for u, v, data in scheduling_graph.edges(data=True): allowed = set(data.get("allowed_pairs") or []) - u_lab = getattr(u, "label") - v_lab = getattr(v, "label") - filt = {(ku, kv) for (ku, kv) in allowed if ku in kept[u_lab] and kv in kept[v_lab]} + u_lab = u.label + v_lab = v.label + filt = { + (ku, kv) for (ku, kv) in allowed if ku in kept[u_lab] and kv in kept[v_lab] + } G2.add_edge(u, v, allowed_pairs=filt) counts_list = [K_by_label[lab] for lab in labels] preferred_counts = [len(preferred_ids.get(lab, set())) for lab in labels] - stats: Dict[str, object] = { + stats: dict[str, object] = { "schedule_counts_by_label": {lab: K_by_label[lab] for lab in labels}, "schedule_counts_summary": _summary(counts_list), - "preferred_count_by_label": {lab: int(len(preferred_ids.get(lab, set()))) for lab in labels}, + "preferred_count_by_label": { + lab: len(preferred_ids.get(lab, set())) for lab in labels + }, "preferred_counts_summary": _summary(preferred_counts), - "selected_count_by_label": {lab: int(len(kept[lab])) for lab in labels}, + "selected_count_by_label": {lab: len(kept[lab]) for lab in labels}, "params": {"M": int(M)}, } diff --git a/ACID/src/acid/solver/schedule_solver.py b/ACID/src/acid/solver/schedule_solver.py index b8cbc5d..dddacea 100644 --- a/ACID/src/acid/solver/schedule_solver.py +++ b/ACID/src/acid/solver/schedule_solver.py @@ -1,7 +1,6 @@ from __future__ import annotations -from acid.defects.quasi import QuasiStabiliser, QuasiProduct - +from acid.defects.quasi import QuasiProduct """ ScheduleSolver — CP-SAT scheduler with product-stabiliser iteration constraints. @@ -10,7 +9,7 @@ measuring product stabilisers via sequential measurement of quasi-stabilisers, subject to ordering constraints derived from an anti-commutation graph. -Design notes and mapping to the user’s proposal: +Design notes and mapping to the user's proposal: - We reuse the stabiliser types and schedule machinery from solver.solver (StabiliserTemplate, Stabiliser, StabiliserSchedule, SyndromeExtractionLayer). @@ -73,8 +72,6 @@ usual per-layer compatibility and the product iteration constraints. """ -from dataclasses import dataclass -from typing import Dict, List, Tuple, Set, Iterable, Optional import itertools import networkx as nx @@ -83,8 +80,8 @@ # Reuse core types from the base solver from acid.scheduling.types import ( Stabiliser, - StabiliserTemplate, StabiliserSchedule, + StabiliserTemplate, SyndromeExtractionLayer, ) @@ -92,19 +89,19 @@ class SchedulingError(Exception): pass + class SchedulingInfeasibleError(SchedulingError): pass + class SchedulingTimeLimitError(SchedulingError): pass + class SchedulingModelInvalidError(SchedulingError): pass - - - class ScheduleSolver: """Scheduling solver with product-stabiliser constraints. @@ -124,10 +121,10 @@ class ScheduleSolver: def __init__( self, connectivity_graph: nx.Graph, - stabilisers: List[Tuple[StabiliserTemplate, List[int], str]], + stabilisers: list[tuple[StabiliserTemplate, list[int], str]], *, anticommutation_graph: nx.Graph, - product_stabilisers: List[QuasiProduct], + product_stabilisers: list[QuasiProduct], ) -> None: # Standalone initialisation (no inheritance from Code) self.num_qubits = connectivity_graph.number_of_nodes() @@ -137,9 +134,9 @@ def __init__( # Compute schedule interoperability structures self.shape_neighbours = self.get_shape_neighbours() self.schedule_dependencies = self.calculate_schedule_dependencies() - self.scheduling_graph = self.create_shedule_graph() + self.scheduling_graph = self.create_schedule_graph() self.anticomm_graph: nx.Graph = anticommutation_graph.copy() - self.product_specs: List[QuasiProduct] = list(product_stabilisers) + self.product_specs: list[QuasiProduct] = list(product_stabilisers) # Validate that anticomm graph nodes match our stabiliser labels stab_labels = set(self.stabilisers.keys()) @@ -151,13 +148,17 @@ def __init__( # Validate products: labels exist and types match for ps in self.product_specs: - if ps.pauli_type not in ('X', 'Z'): - raise ValueError(f"Product {ps.label} has invalid pauli_type: {ps.pauli_type}") + if ps.pauli_type not in ("X", "Z"): + raise ValueError( + f"Product {ps.label} has invalid pauli_type: {ps.pauli_type}" + ) if not ps.members: raise ValueError(f"Product {ps.label} has no members") for m in ps.members: if m not in self.stabilisers: - raise ValueError(f"Product {ps.label} references unknown stabiliser label: {m}") + raise ValueError( + f"Product {ps.label} references unknown stabiliser label: {m}" + ) if self.stabilisers[m].pauli_type != ps.pauli_type: raise ValueError( f"Product {ps.label} pauli_type {ps.pauli_type} does not match member {m} type {self.stabilisers[m].pauli_type}" @@ -171,61 +172,93 @@ def __init__( # Build quick lookup structures for product membership and anticomm products self._build_product_indices() # Optional pruning state (populated via apply_pruning) - self._prune_allowed_ids_by_label: Dict[str, List[int]] | None = None + self._prune_allowed_ids_by_label: dict[str, list[int]] | None = None self._pruned_graph: nx.DiGraph | None = None def apply_pruning(self, *, M: int, verbose: bool = False) -> None: from .prune import prune_schedule_graph + res = prune_schedule_graph(self.scheduling_graph, M, verbose=verbose) - self._prune_allowed_ids_by_label = {lab: sorted(list(xs)) for lab, xs in res.allowed_per_label.items()} + self._prune_allowed_ids_by_label = { + lab: sorted(xs) for lab, xs in res.allowed_per_label.items() + } self._pruned_graph = res.filtered_graph # --- Compatibility helpers (copied from legacy Code class) --- def make_stabilisers(self, stabilisers) -> dict[str, Stabiliser]: - stabiliser_objs: Dict[str, Stabiliser] = {} + """Builds Stabiliser objects from the provided stabiliser templates and qubit maps.""" + stabiliser_objs: dict[str, Stabiliser] = {} for template, qubits, label in stabilisers: stabiliser = template.make_stabiliser(qubits, label) for u, v in stabiliser.connectivity_subgraph.edges: - assert self.connectivity_graph.has_edge(stabiliser.qubit_map[u], stabiliser.qubit_map[v]), \ - "Stabiliser connectivity not compatible with code connectivity" + assert self.connectivity_graph.has_edge( + stabiliser.qubit_map[u], stabiliser.qubit_map[v] + ), "Stabiliser connectivity not compatible with code connectivity" assert label not in stabiliser_objs, f"Duplicate stabiliser label {label}" stabiliser_objs[label] = stabiliser return stabiliser_objs def get_shape_neighbours(self): template_neighbours = set() - for stab1_unsorted, stab2_unsorted in itertools.combinations(self.stabilisers.values(), 2): - stab1, stab2 = sorted([stab1_unsorted, stab2_unsorted], - key=lambda s: (s.stabiliser_template.template_id, tuple(s.qubit_map_reverse))) - overlap_12 = {stab1.qubit_map_reverse[q]: stab2.qubit_map_reverse[q] for q in sorted(stab1.qubit_set.intersection(stab2.qubit_set))} + for stab1_unsorted, stab2_unsorted in itertools.combinations( + self.stabilisers.values(), 2 + ): + stab1, stab2 = sorted( + [stab1_unsorted, stab2_unsorted], + key=lambda s: ( + s.stabiliser_template.template_id, + tuple(s.qubit_map_reverse), + ), + ) + overlap_12 = { + stab1.qubit_map_reverse[q]: stab2.qubit_map_reverse[q] + for q in sorted(stab1.qubit_set.intersection(stab2.qubit_set)) + } if not overlap_12: continue template_neighbours.add( - (stab1.stabiliser_template, stab2.stabiliser_template, tuple(overlap_12.keys()), tuple(overlap_12.values()))) + ( + stab1.stabiliser_template, + stab2.stabiliser_template, + tuple(overlap_12.keys()), + tuple(overlap_12.values()), + ) + ) return list(template_neighbours) def calculate_schedule_dependencies(self): import os + verbose_build = os.environ.get("FAB_SCHEDULE_BUILD_VERBOSE", "0") == "1" dependencies = {} it_pairs = self.shape_neighbours if verbose_build: try: from tqdm import tqdm # type: ignore + it_pairs = tqdm(list(it_pairs), desc="[build] dep pairs", leave=False) except Exception: pass for template1, template2, indices1, indices2 in it_pairs: - key = (template1.template_id, template2.template_id, tuple(sorted(zip(indices1, indices2)))) + key = ( + template1.template_id, + template2.template_id, + tuple(sorted(zip(indices1, indices2))), + ) dependencies[key] = [] common_qubits = dict(zip(indices1, indices2)) iter_s1 = enumerate(template1.schedules) if verbose_build: try: from tqdm import tqdm # type: ignore + iter_s1 = enumerate(template1.schedules) inner_total = len(template1.schedules) * len(template2.schedules) - pbar = tqdm(total=inner_total, desc=f"[build] deps {template1.name or template1.template_id}-{template2.name or template2.template_id}", leave=False) + pbar = tqdm( + total=inner_total, + desc=f"[build] deps {template1.name or template1.template_id}-{template2.name or template2.template_id}", + leave=False, + ) except Exception: pbar = None else: @@ -240,16 +273,28 @@ def calculate_schedule_dependencies(self): pbar.close() return dependencies - def create_shedule_graph(self): + def create_schedule_graph(self): + """Creates the schedule graph. + + Nodes are stabilisers. An edge between stabilisers indicates that there is at least one + incompatible schedule combination between two stabilisers. The edge data contains + the allowed schedule index pairs for the two stabilisers, which are compatible and can be + scheduled together.""" import os + verbose_build = os.environ.get("FAB_SCHEDULE_BUILD_VERBOSE", "0") == "1" + # Nodes are stabilisers; an edge means the pair has at least one + # incompatible schedule combination that must be constrained in CP-SAT. scheduling_graph = nx.DiGraph() scheduling_graph.add_nodes_from(self.stabilisers.values()) it_stabs = list(self.stabilisers.values()) if verbose_build: try: from tqdm import tqdm # type: ignore - it_prog = tqdm(range(len(it_stabs)), desc="[build] sched graph", leave=False) + + it_prog = tqdm( + range(len(it_stabs)), desc="[build] sched graph", leave=False + ) except Exception: it_prog = None else: @@ -263,7 +308,12 @@ def _median(vals: list[int]) -> float: return 0.0 s = sorted(vals) n = len(s) - return float(s[n//2]) if (n % 2 == 1) else 0.5 * float(s[n//2-1] + s[n//2]) + return ( + float(s[n // 2]) + if (n % 2 == 1) + else 0.5 * float(s[n // 2 - 1] + s[n // 2]) + ) + for stab_1_i_unsorted, stab1_unsorted in enumerate(it_stabs): qubit_set1 = stab1_unsorted.qubit_set template1 = stab1_unsorted.stabiliser_template @@ -272,21 +322,42 @@ def _median(vals: list[int]) -> float: node_sched_counts.append(len(template1.schedules)) except Exception: pass - for stab2_unsorted in list(self.stabilisers.values())[stab_1_i_unsorted+1:]: + # Only consider each unordered stabiliser pair once. + for stab2_unsorted in list(self.stabilisers.values())[ + stab_1_i_unsorted + 1 : + ]: overlap = qubit_set1.intersection(stab2_unsorted.qubit_set) + # Disjoint stabilisers cannot conflict in the same layer. if not overlap: continue - stab1, stab2 = sorted([stab1_unsorted, stab2_unsorted], - key=lambda s: (s.stabiliser_template.template_id, tuple(s.qubit_map_reverse))) - mapping = {stab1.qubit_map_reverse[q]: stab2.qubit_map_reverse[q] for q in stab1.qubit_set.intersection(stab2.qubit_set)} - key = (stab1.stabiliser_template.template_id, stab2.stabiliser_template.template_id, tuple(sorted(zip(mapping.keys(), mapping.values())))) - if len(self.schedule_dependencies[key]) == len(stab1.stabiliser_template.schedules) * len(stab2.stabiliser_template.schedules): + stab1, stab2 = sorted( + [stab1_unsorted, stab2_unsorted], + key=lambda s: ( + s.stabiliser_template.template_id, + tuple(s.qubit_map_reverse), + ), + ) + mapping = { + stab1.qubit_map_reverse[q]: stab2.qubit_map_reverse[q] + for q in stab1.qubit_set.intersection(stab2.qubit_set) + } + key = ( + stab1.stabiliser_template.template_id, + stab2.stabiliser_template.template_id, + tuple(sorted(mapping.items())), + ) + # If every schedule pair is compatible, no edge/constraint needed. + if len(self.schedule_dependencies[key]) == len( + stab1.stabiliser_template.schedules + ) * len(stab2.stabiliser_template.schedules): continue ap = self.schedule_dependencies[key] try: edge_allowed_counts.append(len(ap)) except Exception: pass + # Store compatible schedule index pairs for this overlapping pair. + # The solver later forbids combinations not listed in allowed_pairs. scheduling_graph.add_edge(stab1, stab2, allowed_pairs=ap) if it_prog is not None: # Update running stats in progress bar postfix @@ -295,14 +366,18 @@ def _median(vals: list[int]) -> float: ns_med = _median(node_sched_counts) ns_max = max(node_sched_counts) if node_sched_counts else 0 ea_min = min(edge_allowed_counts) if edge_allowed_counts else 0 - ea_med = _median(edge_allowed_counts) if edge_allowed_counts else 0.0 + ea_med = ( + _median(edge_allowed_counts) if edge_allowed_counts else 0.0 + ) ea_max = max(edge_allowed_counts) if edge_allowed_counts else 0 - it_prog.set_postfix({ - "nodes": f"{len(node_sched_counts)}", - "K[min/med/max]": f"{ns_min}/{int(ns_med) if ns_med.is_integer() else ns_med}/{ns_max}", - "edges": f"{len(edge_allowed_counts)}", - "AP[min/med/max]": f"{ea_min}/{int(ea_med) if isinstance(ea_med, float) and ea_med.is_integer() else ea_med}/{ea_max}", - }) + it_prog.set_postfix( + { + "nodes": f"{len(node_sched_counts)}", + "K[min/med/max]": f"{ns_min}/{int(ns_med) if ns_med.is_integer() else ns_med}/{ns_max}", + "edges": f"{len(edge_allowed_counts)}", + "AP[min/med/max]": f"{ea_min}/{int(ea_med) if isinstance(ea_med, float) and ea_med.is_integer() else ea_med}/{ea_max}", + } + ) except Exception: pass it_prog.update(1) @@ -330,17 +405,25 @@ def _verify_expected_commutations(self) -> None: ) def _build_product_indices(self) -> None: + """Builds lookup structures for product membership and opposite-type products per + stabiliser.""" # Map product label -> ProductSpec and member Stabiliser objects - self.products_by_label: Dict[str, QuasiProduct] = {p.label: p for p in self.product_specs} + self.plabel_to_product: dict[str, QuasiProduct] = { + p.label: p for p in self.product_specs + } # Stabiliser label -> list of product labels of same type containing it - self.products_by_member: Dict[str, List[str]] = {lab: [] for lab in self.stabilisers} + self.qstab_to_product: dict[str, list[str]] = { + lab: [] for lab in self.stabilisers + } for p in self.product_specs: for m in p.members: - self.products_by_member[m].append(p.label) + self.qstab_to_product[m].append(p.label) # For each stabiliser label q, collect opposite-type products that contain # any anticomm neighbor of q - self.opp_products_by_label: Dict[str, Set[str]] = {lab: set() for lab in self.stabilisers} + self.opp_products_by_label: dict[str, set[str]] = { + lab: set() for lab in self.stabilisers + } for u, v in self.anticomm_graph.edges(): # u-v anticommute; add products of type(v) to u, and type(u) to v su, sv = self.stabilisers[u], self.stabilisers[v] @@ -358,7 +441,7 @@ def create_layers_with_products( self, num_layers: int, solve_time: float = 10.0, - ) -> List[SyndromeExtractionLayer]: + ) -> list[SyndromeExtractionLayer]: """Build and solve CP-SAT with product/iteration constraints. Returns a list of SyndromeExtractionLayer objects, one per layer. @@ -366,9 +449,14 @@ def create_layers_with_products( model = cp_model.CpModel() # Optional pruning already applied in prepare_solver - allowed_ids_by_label: Dict[str, List[int]] = {} - if self._prune_allowed_ids_by_label is not None and self._pruned_graph is not None: - allowed_ids_by_label = {lab: list(ids) for lab, ids in self._prune_allowed_ids_by_label.items()} + allowed_ids_by_label: dict[str, list[int]] = {} + if ( + self._prune_allowed_ids_by_label is not None + and self._pruned_graph is not None + ): + allowed_ids_by_label = { + lab: list(ids) for lab, ids in self._prune_allowed_ids_by_label.items() + } scheduling_graph = self._pruned_graph else: scheduling_graph = self.scheduling_graph @@ -376,115 +464,150 @@ def create_layers_with_products( K = len(stab.stabiliser_template.schedules) allowed_ids_by_label[stab.label] = list(range(K)) - # Decision variables: assignment[label][t][k] + # Decision variables: assignment[stabiliser label][layer_num][k] # where k indexes schedules for that stabiliser template. - assignment: Dict[str, List[Dict[int, cp_model.IntVar]]] = {} - measured: Dict[str, List[cp_model.IntVar]] = {} + assignment: dict[str, list[dict[int, cp_model.IntVar]]] = {} + measured: dict[str, list[cp_model.IntVar]] = {} for stab in self.stabilisers.values(): - kept_ids = allowed_ids_by_label.get(stab.label) - if not kept_ids: + kept_schedule_ids = allowed_ids_by_label.get(stab.label) + if not kept_schedule_ids: raise RuntimeError(f"No allowed schedules for stabiliser {stab.label}") - per_layer: List[Dict[int, cp_model.IntVar]] = [] - measured_layer: List[cp_model.IntVar] = [] - for t in range(num_layers): - var_map: Dict[int, cp_model.IntVar] = {} - for k_id in kept_ids: - var_map[k_id] = model.NewBoolVar(f"assign__{stab.label}__t{t}__k{k_id}") + per_layer: list[dict[int, cp_model.IntVar]] = [] + measured_layer: list[cp_model.IntVar] = [] + for layer_num in range(num_layers): + var_map: dict[int, cp_model.IntVar] = {} + for k_schedule_id in kept_schedule_ids: + # did we assign schedule k to this stabiliser at this layer? + var_map[k_schedule_id] = model.new_bool_var( + f"assign__{stab.label}__t{layer_num}__k{k_schedule_id}" + ) # At most one schedule for this stabiliser in this layer - model.Add(sum(var_map.values()) <= 1) + model.add(sum(var_map.values()) <= 1) per_layer.append(var_map) - m = model.NewBoolVar(f"measured__{stab.label}__t{t}") - model.Add(sum(var_map.values()) == m) + m = model.new_bool_var(f"measured__{stab.label}__t{layer_num}") + model.add(sum(var_map.values()) == m) measured_layer.append(m) # Schedule hint only if it exists and is kept ds = getattr(stab.stabiliser_template, "schedule_hint_index", None) dl = getattr(stab.stabiliser_template, "layer_hint", None) - if ds is not None and dl is not None and dl == t and ds in var_map: + if ( + ds is not None + and dl is not None + and dl == layer_num + and ds in var_map + ): # Hint: prefer this schedule at this layer - model.AddHint(var_map[ds], 1) + model.add_hint(var_map[ds], 1) assignment[stab.label] = per_layer measured[stab.label] = measured_layer # Coverage: every stabiliser must be measured at least once across layers for lab, mlist in measured.items(): - model.Add(sum(mlist) >= 1) + model.add(sum(mlist) >= 1) # Compatibility constraints per layer, using precomputed scheduling_graph for u, v in scheduling_graph.edges(): data = scheduling_graph.get_edge_data(u, v) - allowed = set(data['allowed_pairs']) + allowed = set(data["allowed_pairs"]) u_allowed_ids = allowed_ids_by_label[u.label] v_allowed_ids = allowed_ids_by_label[v.label] - for t in range(num_layers): - u_map = assignment[u.label][t] - v_map = assignment[v.label][t] + for layer_num in range(num_layers): + u_map = assignment[u.label][layer_num] + v_map = assignment[v.label][layer_num] for ku in u_allowed_ids: for kv in v_allowed_ids: if (ku, kv) not in allowed: - model.Add(u_map[ku] + v_map[kv] <= 1) + # Incompatible pair: cannot assign ku to u and kv to v + # in the same layer so should sum to less than or equal to 1 + model.add(u_map[ku] + v_map[kv] <= 1) # --- Product iteration variables and constraints --- # For each product P and layer t: - # c_P[t] ∈ [0..num_layers] - # f_{P,i}[t] for each member i - # Reset_P[t] for t>=1: AND_i f_{P,i}[t-1] + # c_P[t] ∈ [0..num_layers] - how many times P has been measured up to layer t + # f_{P,i}[t] for each member i - whether quasi stabilser i of P has been measured in the current layer + # Reset_P[t] for t>=1: AND_i f_{P,i}[t-1]`` # c_P[t] = c_P[t-1] + Reset_P[t] (t>=1); c_P[0] = 0 # If Reset_P[t]: f_{P,i}[t] = 0; else f_{P,i}[t] = OR(f_{P,i}[t-1], measured(i, t)) ###### SHOULD BE if reset f{P,i}[t] = measured(i, t) - product_counters: Dict[str, List[cp_model.IntVar]] = {} - product_flags: Dict[str, Dict[str, List[cp_model.IntVar]]] = {} - product_inprogress: Dict[str, List[cp_model.IntVar]] = {} - product_reset: Dict[str, List[cp_model.IntVar]] = {} + product_counters: dict[str, list[cp_model.IntVar]] = {} + product_flags: dict[str, dict[str, list[cp_model.IntVar]]] = {} + product_inprogress: dict[str, list[cp_model.IntVar]] = {} + product_reset: dict[str, list[cp_model.IntVar]] = {} for p in self.product_specs: # counters - product_counters[p.label] = [model.NewIntVar(0, num_layers, f"ctr__{p.label}__t{t}") for t in range(num_layers)] - product_inprogress[p.label] = [model.NewBoolVar(f"inprog__{p.label}__t{t}") for t in range(num_layers)] + product_counters[p.label] = [ + model.new_int_var(0, num_layers, f"ctr__{p.label}__t{t}") + for t in range(num_layers) + ] + product_inprogress[p.label] = [ + model.new_bool_var(f"inprog__{p.label}__t{t}") + for t in range(num_layers) + ] # member flags per layer - flags_for_members: Dict[str, List[cp_model.IntVar]] = {} + flags_for_members: dict[str, list[cp_model.IntVar]] = {} for m in p.members: - flags_for_members[m] = [model.NewBoolVar(f"flag__{p.label}__{m}__t{t}") for t in range(num_layers)] + flags_for_members[m] = [ + model.new_bool_var(f"flag__{p.label}__{m}__t{t}") + for t in range(num_layers) + ] product_flags[p.label] = flags_for_members # resets (t>=1); for t=0 use constant 0 via a fixed false bool - reset_vars: List[cp_model.IntVar] = [] - for t in range(num_layers): - if t == 0: - r = model.NewBoolVar(f"reset__{p.label}__t0") - model.Add(r == 0) + reset_vars: list[cp_model.IntVar] = [] + for layer_num in range(num_layers): + if layer_num == 0: + reset_var = model.new_bool_var(f"reset__{p.label}__t0") + model.add(reset_var == 0) else: - r = model.NewBoolVar(f"reset__{p.label}__t{t}") + reset_var = model.new_bool_var(f"reset__{p.label}__t{layer_num}") # r == AND_i f_{i}[t-1] # decompose AND via AddBoolAnd and AndBoolOr - prev_flags = [flags_for_members[m][t - 1] for m in p.members] - model.AddBoolAnd(prev_flags).OnlyEnforceIf(r) - model.AddBoolOr([f.Not() for f in prev_flags]).OnlyEnforceIf(r.Not()) - reset_vars.append(r) + prev_flags = [ + flags_for_members[m][layer_num - 1] for m in p.members + ] + model.add_bool_and(prev_flags).only_enforce_if(reset_var) + model.add_bool_or([f.Not() for f in prev_flags]).only_enforce_if( + reset_var.Not() + ) + reset_vars.append(reset_var) # In-progress flag is true iff any of the member flags is true - model.AddMaxEquality(product_inprogress[p.label][t], - [flags_for_members[m][t] for m in p.members]) + model.add_max_equality( + product_inprogress[p.label][layer_num], + [flags_for_members[m][layer_num] for m in p.members], + ) product_reset[p.label] = reset_vars # counter recurrence and flag recurrence # c[0] = 0 c = product_counters[p.label] - model.Add(c[0] == 0) + model.add(c[0] == 0) # t >= 1: c[t] = c[t-1] + reset[t] - for t in range(1, num_layers): - model.Add(c[t] == c[t - 1] + reset_vars[t]) + for layer_num in range(1, num_layers): + model.add(c[layer_num] == c[layer_num - 1] + reset_vars[layer_num]) # flag update for m in p.members: f = flags_for_members[m] # t = 0: f[0] = measured(m, 0) - model.Add(f[0] == measured[m][0]) - for t in range(1, num_layers): + model.add(f[0] == measured[m][0]) + for layer_num in range(1, num_layers): # If reset[t] then f[t] = measured(m, t) - model.Add(f[t] == measured[m][t]).OnlyEnforceIf(reset_vars[t]) + model.add(f[layer_num] == measured[m][layer_num]).only_enforce_if( + reset_vars[layer_num] + ) # Else f[t] = OR(f[t-1], measured(m,t)) - not_reset = reset_vars[t].Not() - model.Add(f[t] >= f[t - 1]).OnlyEnforceIf(not_reset) - model.Add(f[t] >= measured[m][t]).OnlyEnforceIf(not_reset) - model.Add(f[t] <= f[t - 1] + measured[m][t]).OnlyEnforceIf(not_reset) + not_reset = reset_vars[layer_num].Not() + + # linearisation of OR(f[t-1], measured(m,t)) via inequalities: + model.add(f[layer_num] >= f[layer_num - 1]).only_enforce_if( + not_reset + ) + model.add(f[layer_num] >= measured[m][layer_num]).only_enforce_if( + not_reset + ) + model.add( + f[layer_num] <= f[layer_num - 1] + measured[m][layer_num] + ).only_enforce_if(not_reset) # --- Cross-product gating constraints --- # If measured(q, t) then: @@ -494,61 +617,64 @@ def create_layers_with_products( # Uncomment the main gating when opp_products/same_products are defined and valid. for q_label, stab in self.stabilisers.items(): q_type = stab.pauli_type - same_products = self.products_by_member.get(q_label, []) + # product stabiliers that contain q_label + same_products = self.qstab_to_product.get(q_label, []) + # product stabilers that contain any quasi that anticommutes with q_label opp_products = sorted(self.opp_products_by_label.get(q_label, set())) if same_products: if not opp_products: continue # nothing to gate - for t in range(num_layers): - mqt = measured[q_label][t] - if q_type == 'X': + for layer_num in range(num_layers): + mqt = measured[q_label][layer_num] + if q_type == "X": for pz_label in opp_products: - cz = product_counters[pz_label][t] + cz = product_counters[pz_label][layer_num] for px_label in same_products: - cx = product_counters[px_label][t] - model.Add(cx == cz).OnlyEnforceIf(mqt) + cx = product_counters[px_label][layer_num] + model.add(cx == cz).only_enforce_if(mqt) else: # 'Z' for px_label in opp_products: - cx = product_counters[px_label][t] + cx = product_counters[px_label][layer_num] for pz_label in same_products: - cz = product_counters[pz_label][t] + cz = product_counters[pz_label][layer_num] # strict > as cx >= cz + 1 - model.Add(cx >= cz + 1).OnlyEnforceIf(mqt) + model.add(cx >= cz + 1).only_enforce_if(mqt) else: # Orphan quasi stabiliser: forbid measuring q in any layer where an # anticomm-opposite product is in-progress (any member flagged in the # current iteration). Implement as m(q,t) + inprogress(P_opp,t) <= 1. if not opp_products: continue - for t in range(num_layers): - mqt = measured[q_label][t] + for layer_num in range(num_layers): + mqt = measured[q_label][layer_num] for p_opp_label in opp_products: - inprog = product_inprogress[p_opp_label][t] - model.Add(mqt + inprog <= 1) - - + inprog = product_inprogress[p_opp_label][layer_num] + model.add(mqt + inprog <= 1) # Objective: big-M lexicographic maximize (min_group_coverage, total_quasi_measured) # Build group totals: products use their final counter; non-product stabs use sum of measured flags. - group_totals: List[cp_model.IntVar] = [] + group_totals: list[cp_model.IntVar] = [] for p in self.product_specs: group_totals.append(product_counters[p.label][-1]) for lab, stab in self.stabilisers.items(): - if not self.products_by_member.get(lab, []): - cnt = model.NewIntVar(0, num_layers, f"count__{lab}") - model.Add(cnt == sum(measured[lab])) + if not self.qstab_to_product.get(lab, []): + cnt = model.new_int_var(0, num_layers, f"count__{lab}") + model.add(cnt == sum(measured[lab])) group_totals.append(cnt) # z <= each group; maximization pushes z to the minimum of the groups - z = model.NewIntVar(0, num_layers, "min_group_coverage") + # z is the minium times any product or non-product stabiliser has been measured across + # all layers + z = model.new_int_var(0, num_layers, "min_group_coverage") for g in group_totals: - model.Add(z <= g) + model.add(z <= g) # Tie breaker: total measured across all stabs - total_quasi = model.NewIntVar(0, len(self.stabilisers) * num_layers, "total_quasi_measured") - model.Add(total_quasi == sum(sum(measured[lab]) for lab in self.stabilisers)) + total_quasi = model.new_int_var( + 0, len(self.stabilisers) * num_layers, "total_quasi_measured" + ) + model.add(total_quasi == sum(sum(measured[lab]) for lab in self.stabilisers)) # Big-M weighting M = len(self.stabilisers) * num_layers + 1 - model.Maximize(z * M + total_quasi) - + model.maximize(z * M + total_quasi) solver = cp_model.CpSolver() solver.parameters.max_time_in_seconds = float(solve_time) @@ -562,23 +688,29 @@ def create_layers_with_products( except Exception: status_name = str(status) if status == cp_model.INFEASIBLE: - raise SchedulingInfeasibleError(f"Proven infeasible (L={num_layers}, time_limit={solve_time}s)") + raise SchedulingInfeasibleError( + f"Proven infeasible (L={num_layers}, time_limit={solve_time}s)" + ) if status == cp_model.MODEL_INVALID: raise SchedulingModelInvalidError("Model invalid") # Otherwise, treat as time limit / unknown - raise SchedulingTimeLimitError(f"Time limit or unknown status ({status_name}) with no feasible solution found (L={num_layers}, time_limit={solve_time}s)") + raise SchedulingTimeLimitError( + f"Time limit or unknown status ({status_name}) with no feasible solution found (L={num_layers}, time_limit={solve_time}s)" + ) - layers: List[SyndromeExtractionLayer] = [] - for t in range(num_layers): - chosen: Dict[Stabiliser, StabiliserSchedule] = {} + layers: list[SyndromeExtractionLayer] = [] + for layer_num in range(num_layers): + chosen: dict[Stabiliser, StabiliserSchedule] = {} for stab in self.stabilisers.values(): - var_map = assignment[stab.label][t] # Dict[int(schedule_id) -> IntVar] + var_map = assignment[stab.label][ + layer_num + ] # Dict[int(schedule_id) -> IntVar] # iterate actual ids and vars - picked = False - for k_id, var in var_map.items(): + for k_schedule_id, var in var_map.items(): if solver.Value(var) == 1: - chosen[stab] = stab.stabiliser_template.schedules[int(k_id)] - picked = True + chosen[stab] = stab.stabiliser_template.schedules[ + int(k_schedule_id) + ] break # It is valid that a stabiliser is not measured in a given layer (<=1 per layer and sum across layers >=1) layers.append(SyndromeExtractionLayer(chosen=chosen, code=self)) diff --git a/ACID/src/acid/stim_to_shatter_url.py b/ACID/src/acid/stim_to_shatter_url.py index 2f787e0..7cf79b9 100644 --- a/ACID/src/acid/stim_to_shatter_url.py +++ b/ACID/src/acid/stim_to_shatter_url.py @@ -9,10 +9,9 @@ to open the Shatter web app with the circuit embedded in the URL fragment. """ +import webbrowser from pathlib import Path from urllib.parse import quote -import webbrowser - _SHATTER_BASE = "https://stasiu51.github.io/Shatter/#circuit=" @@ -42,7 +41,9 @@ def prompt_open_shatter(stim_path: str) -> None: return url = build_shatter_url_from_text(text) try: - input("Press enter to open Shatter to visualise the circuit; or ctrl-c to cancel: ") + input( + "Press enter to open Shatter to visualise the circuit; or ctrl-c to cancel: " + ) except KeyboardInterrupt: print("\n[cancelled] Not opening Shatter.") return @@ -51,4 +52,3 @@ def prompt_open_shatter(stim_path: str) -> None: print("[ok] Opened Shatter in your default browser.") except Exception as e: print(f"[warn] Failed to open browser: {e}") - diff --git a/ACID/src/acid/tableau_visualiser/__init__.py b/ACID/src/acid/tableau_visualiser/__init__.py index 95a5bc7..7669d55 100644 --- a/ACID/src/acid/tableau_visualiser/__init__.py +++ b/ACID/src/acid/tableau_visualiser/__init__.py @@ -1,2 +1 @@ """Stim tableau visualisation helpers.""" - diff --git a/ACID/src/acid/tableau_visualiser/basis.py b/ACID/src/acid/tableau_visualiser/basis.py index e8e0e8f..148c52d 100644 --- a/ACID/src/acid/tableau_visualiser/basis.py +++ b/ACID/src/acid/tableau_visualiser/basis.py @@ -1,11 +1,11 @@ from __future__ import annotations from dataclasses import dataclass -from typing import List, Literal +from typing import Literal from ..gf2_utils import gf2_rank -PauliKind = Literal['stabiliser', 'gauge', 'logical'] +PauliKind = Literal["stabiliser", "gauge", "logical"] @dataclass @@ -13,35 +13,37 @@ class PauliBasis: name: str kind: PauliKind priority: int - rows: List[List[int]] # each row length 2n (X|Z) representation over GF(2) + rows: list[list[int]] # each row length 2n (X|Z) representation over GF(2) def validate(self, n: int) -> None: for r in self.rows: if len(r) != 2 * n: - raise ValueError(f"Basis {self.name} has row with wrong length (expected {2*n})") + raise ValueError( + f"Basis {self.name} has row with wrong length (expected {2 * n})" + ) # Check linear independence (not strictly required, but recommended) if gf2_rank(self.rows) != len(self.rows): raise ValueError(f"Basis {self.name} rows are not linearly independent") -def pauli_to_bin_row(pauli: str) -> List[int]: +def pauli_to_bin_row(pauli: str) -> list[int]: """Convert a Pauli string like '+X_Z' into a 2n binary row [X...|Z...]. Ignores the sign and underscores. Y -> X=1, Z=1. """ s = pauli.strip() - if s and s[0] in '+-': + if s and s[0] in "+-": s = s[1:] - qubits = [c for c in s if c in 'XYZI_'] + qubits = [c for c in s if c in "XYZI_"] n = len(qubits) X = [0] * n Z = [0] * n for i, c in enumerate(qubits): - if c == 'X': + if c == "X": X[i] = 1 - elif c == 'Z': + elif c == "Z": Z[i] = 1 - elif c == 'Y': + elif c == "Y": X[i] = 1 Z[i] = 1 else: @@ -56,7 +58,7 @@ def default_single_qubit_basis(n: int) -> PauliBasis: Ordering: all Z_i for i in [0..n-1], then all X_i. Kind: 'stabiliser', priority 0. """ - rows: List[List[int]] = [] + rows: list[list[int]] = [] # Z_i for i in range(n): X = [0] * n @@ -69,5 +71,6 @@ def default_single_qubit_basis(n: int) -> PauliBasis: Z = [0] * n X[i] = 1 rows.append(X + Z) - return PauliBasis(name="Single Qubit Paulis", kind='stabiliser', priority=0, rows=rows) - + return PauliBasis( + name="Single Qubit Paulis", kind="stabiliser", priority=0, rows=rows + ) diff --git a/ACID/src/acid/tableau_visualiser/cli.py b/ACID/src/acid/tableau_visualiser/cli.py index b66bd92..18cb61f 100644 --- a/ACID/src/acid/tableau_visualiser/cli.py +++ b/ACID/src/acid/tableau_visualiser/cli.py @@ -3,16 +3,16 @@ import argparse import json from pathlib import Path -from typing import List, Dict import stim +from acid.pauli import CommutingPauliBasis, PauliString + from .basis import default_single_qubit_basis from .visualiser import TableauVisualiser -from acid.pauli import CommutingPauliBasis, PauliString, AntiCommutingPauliBasis -def load_commuting_bases(path: Path, n: int) -> List[CommutingPauliBasis]: +def load_commuting_bases(path: Path, n: int) -> list[CommutingPauliBasis]: """Load commuting bases from a JSON file. Supported format: @@ -23,22 +23,30 @@ def load_commuting_bases(path: Path, n: int) -> List[CommutingPauliBasis]: Rows are 2n binary (X|Z). Non-'stabiliser' kinds are ignored. """ data = json.loads(path.read_text()) - out: List[CommutingPauliBasis] = [] + out: list[CommutingPauliBasis] = [] for obj in data: - if str(obj.get('kind','stabiliser')).lower() != 'stabiliser': + if str(obj.get("kind", "stabiliser")).lower() != "stabiliser": continue - name = str(obj.get('name', 'User Basis')) - prio = int(obj.get('priority', 0)) - rows = [PauliString.from_2n(list(map(int, r))) for r in obj.get('rows', [])] + name = str(obj.get("name", "User Basis")) + prio = int(obj.get("priority", 0)) + rows = [PauliString.from_2n(list(map(int, r))) for r in obj.get("rows", [])] out.append(CommutingPauliBasis(name=name, priority=prio, rows=rows)) return out def main() -> int: - ap = argparse.ArgumentParser(description="Tableau visualiser for stim circuits (commuting bases)") + ap = argparse.ArgumentParser( + description="Tableau visualiser for stim circuits (commuting bases)" + ) ap.add_argument("stim_file", type=str, help="Path to .stim circuit") - ap.add_argument("--bases", type=str, help="Optional JSON file defining additional commuting bases") - ap.add_argument("--ticks", type=int, default=0, help="How many TICKs to step (0=all)") + ap.add_argument( + "--bases", + type=str, + help="Optional JSON file defining additional commuting bases", + ) + ap.add_argument( + "--ticks", type=int, default=0, help="How many TICKs to step (0=all)" + ) args = ap.parse_args() circ = stim.Circuit(Path(args.stim_file).read_text()) @@ -47,11 +55,17 @@ def main() -> int: vis = TableauVisualiser(circ, commuting_bases=[], anticommuting_bases={}) n = vis.n - commuting: List[CommutingPauliBasis] = [] + commuting: list[CommutingPauliBasis] = [] # Default single-qubit commuting basis default_basis_2n = default_single_qubit_basis(n) default_rows = [PauliString.from_2n(r) for r in default_basis_2n.rows] - commuting.append(CommutingPauliBasis(name=default_basis_2n.name, priority=default_basis_2n.priority, rows=default_rows)) + commuting.append( + CommutingPauliBasis( + name=default_basis_2n.name, + priority=default_basis_2n.priority, + rows=default_rows, + ) + ) if args.bases: commuting.extend(load_commuting_bases(Path(args.bases), n)) diff --git a/ACID/src/acid/tableau_visualiser/visualiser.py b/ACID/src/acid/tableau_visualiser/visualiser.py index e8cd387..6b85362 100644 --- a/ACID/src/acid/tableau_visualiser/visualiser.py +++ b/ACID/src/acid/tableau_visualiser/visualiser.py @@ -1,26 +1,32 @@ from __future__ import annotations -import stim + from dataclasses import dataclass -from typing import List, Dict, Tuple, Union -from ..gf2_utils import gf2_left_nullspace, gf2_rank, gf2_is_in_span, gf2_are_not_in_span -from acid.pauli import CommutingPauliBasis, AntiCommutingPauliBasis +import stim + +from acid.pauli import AntiCommutingPauliBasis, CommutingPauliBasis +from ..gf2_utils import ( + gf2_is_in_span, + gf2_left_nullspace, + gf2_rank, +) -def pauli_string_to_row(p: stim.PauliString) -> List[int]: + +def pauli_string_to_row(p: stim.PauliString) -> list[int]: s = str(p) - if s and s[0] in '+-': + if s and s[0] in "+-": s = s[1:] qubits = [c for c in s] n = len(qubits) X = [0] * n Z = [0] * n for i, c in enumerate(qubits): - if c == 'X': + if c == "X": X[i] = 1 - elif c == 'Z': + elif c == "Z": Z[i] = 1 - elif c == 'Y': + elif c == "Y": X[i] = 1 Z[i] = 1 else: @@ -28,16 +34,17 @@ def pauli_string_to_row(p: stim.PauliString) -> List[int]: return X + Z - @dataclass class TableauSnapshot: tick_index: int n: int - stabiliser_sections: List[Tuple[Union[CommutingPauliBasis, AntiCommutingPauliBasis], List[int]]] - logical_descriptions: List[str] + stabiliser_sections: list[ + tuple[CommutingPauliBasis | AntiCommutingPauliBasis, list[int]] + ] + logical_descriptions: list[str] def to_ansi(self) -> str: - out: List[str] = [] + out: list[str] = [] out.append(f"Snapshot @ TICK #{self.tick_index}") out.append("Stabilisers:") if not self.stabiliser_sections: @@ -46,11 +53,13 @@ def to_ansi(self) -> str: for basis, row_indices in self.stabiliser_sections: count = len(row_indices) count_sum += count - preview = ','.join(str(i) for i in row_indices[:8]) + preview = ",".join(str(i) for i in row_indices[:8]) if count == 0: out.append(f" [ {basis.name} ] count=0 of {len(basis.rows)}") else: - out.append(f" [ {basis.name} ] count={count} of {len(basis.rows)} indices=[{preview}{',' if count>8 else ''}{'...' if count>8 else ''}]") + out.append( + f" [ {basis.name} ] count={count} of {len(basis.rows)} indices=[{preview}{',' if count > 8 else ''}{'...' if count > 8 else ''}]" + ) out.append("Logical/Gauges:") if not self.logical_descriptions: @@ -60,13 +69,16 @@ def to_ansi(self) -> str: count_sum += 1 out.append(f" Stabilised by: {s}") out.append(f"Unknown: {self.n - count_sum}") - return '\n'.join(out) + return "\n".join(out) class TableauVisualiser: - def __init__(self, circuit: stim.Circuit, - commuting_bases: List[CommutingPauliBasis], - anticommuting_bases: Dict[str, AntiCommutingPauliBasis]) -> None: + def __init__( + self, + circuit: stim.Circuit, + commuting_bases: list[CommutingPauliBasis], + anticommuting_bases: dict[str, AntiCommutingPauliBasis], + ) -> None: self.circuit = circuit self.instructions = list(circuit) # Determine n from circuit target range (assume qubits 0..max) @@ -74,8 +86,7 @@ def __init__(self, circuit: stim.Circuit, for inst in self.instructions: for t in inst.targets_copy(): if t.is_qubit_target: - if t.value > max_q: - max_q = t.value + max_q = max(max_q, t.value) self.n = max_q + 1 # Sort commuting bases by priority descending self.commuting_bases = list(commuting_bases) @@ -92,11 +103,11 @@ def step_instruction(self) -> bool: return False inst = self.instructions[self.ip] name = inst.name - if name == 'TICK': + if name == "TICK": self.tick_count += 1 self.ip += 1 return True - if name == 'QUBIT_COORDS': + if name == "QUBIT_COORDS": self.ip += 1 return True c = stim.Circuit() @@ -109,23 +120,25 @@ def step_to_next_tick(self) -> bool: while self.ip < len(self.instructions): inst = self.instructions[self.ip] self.step_instruction() - if inst.name == 'TICK': + if inst.name == "TICK": return True return False - def _current_stabilizer_rows(self) -> List[List[int]]: + def _current_stabilizer_rows(self) -> list[list[int]]: stabs = self.sim.canonical_stabilizers() return [pauli_string_to_row(p) for p in stabs] def snapshot(self) -> TableauSnapshot: S_rows = self._current_stabilizer_rows() - chosen_basis_rows: List[List[int]] = [] + chosen_basis_rows: list[list[int]] = [] # Commuting bases membership - sections: List[Tuple[CommutingPauliBasis, AntiCommutingPauliBasis], List[int]] = [] + sections: list[ + tuple[CommutingPauliBasis | AntiCommutingPauliBasis, list[int]] + ] = [] for b in self.commuting_bases[::-1]: - idxs: List[int] = [] + idxs: list[int] = [] for j, p in enumerate(b.rows): row = p.to_2n() if not gf2_is_in_span(row, S_rows): @@ -135,12 +148,11 @@ def snapshot(self) -> TableauSnapshot: idxs.append(j) chosen_basis_rows.append(row) - sections.append((b,idxs)) + sections.append((b, idxs)) # Anti-commuting bases intersections - logical_desc: List[str] = [] + logical_desc: list[str] = [] for label, anti in self.anticommuting_bases.items(): - # M = [B; S], left-nullspace yields combinations B = anti.stacked_2n() M = B + S_rows @@ -149,7 +161,7 @@ def snapshot(self) -> TableauSnapshot: continue p = len(B) kx = len(anti.X_rows) - Y_acc: List[List[int]] = [] + Y_acc: list[list[int]] = [] for w in L: if len(w) != len(M): continue @@ -162,13 +174,13 @@ def snapshot(self) -> TableauSnapshot: if gf2_rank(Y_acc + [yi]) == gf2_rank(Y_acc): continue Y_acc.append(yi) - parts: List[str] = [] + parts: list[str] = [] for j in range(kx): if x[j] & 1: - parts.append(f"X{j+1}") + parts.append(f"X{j + 1}") for j in range(len(anti.Z_rows)): if x[kx + j] & 1: - parts.append(f"Z{j+1}") + parts.append(f"Z{j + 1}") logical_desc.append(f"[{label}] " + ("".join(parts) if parts else "1")) return TableauSnapshot( @@ -177,4 +189,3 @@ def snapshot(self) -> TableauSnapshot: stabiliser_sections=sections, logical_descriptions=logical_desc, ) - diff --git a/README.md b/README.md index 1968b56..b9c4dcd 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,57 @@ This repo contains the core source code that implements ACID as described in my paper [link here]. -The core source code is provided as a python package. To install it into your active python environment, run: +### Installation -`pip install ./ACID` +To simply use ACID, install via pip: -You can then run the examples in /examples, for example by running: +```bash +pip install ./ACID +``` -`python examples/surface_unrotated_grid.py --distance 7 --solve-time 30 --rounds 1 --n-dropped-qubits 1 --n-dropped-couplers 1` +### Running Examples -...which will randomly select 1 qubit and 1 coupler to drop, and create a syndrome extraction circuit of minimal length as a .stim file with some extra markup, and open the result in my visualiser [Shatter](https://stasiu51.github.io/Shatter/), which is based on [Crumble](https://algassert.com/crumble). By default, the circuit produced will not contain a state preparation step, or detector or observable definitions: this is to reduce load when rendered in the visualiser. These can be re-enabled by passing `--output-state-prep` and `--output-detectors-and-observables` to the scripts. +You can run the examples in /examples, for example by running: + +```bash +python examples/surface_unrotated_grid.py --distance 7 --solve-time 30 --rounds 1 --n-dropped-qubits 1 --n-dropped-couplers 1 +``` + +This will randomly select 1 qubit and 1 coupler to drop, and create a syndrome extraction circuit of minimal length as a .stim file with some extra markup, and open the result in my visualiser [Shatter](https://stasiu51.github.io/Shatter/), which is based on [Crumble](https://algassert.com/crumble). By default, the circuit produced will not contain a state preparation step, or detector or observable definitions: this is to reduce load when rendered in the visualiser. These can be re-enabled by passing `--output-state-prep` and `--output-detectors-and-observables` to the scripts. All codes can be run in the defect-free case with `run_all_minimal.sh`. The outputs of this shell file are already available in /visualisations. + +### Development + +#### Install `uv` (Python Package Manager) + +For development, this project uses [uv](https://docs.astral.sh/uv/) for dependency management. Install it with: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +Or use a package manager: +- **macOS**: `brew install uv` +- **Linux**: `pip install uv` or check [docs](https://docs.astral.sh/uv/getting-started/installation/) +- **Windows**: See [installation guide](https://docs.astral.sh/uv/getting-started/installation/) + +#### Setup Development Environment + +To install with dev tools (ruff, ty): + +```bash +uv sync --extra dev +``` + +Or just install dependencies: + +```bash +uv sync +``` + +To run examples during development: + +```bash +uv run examples/surface_unrotated_grid.py --distance 7 --solve-time 30 --rounds 1 --n-dropped-qubits 1 --n-dropped-couplers 1 +``` diff --git a/examples/bb144_deg5_tableau.py b/examples/bb144_deg5_tableau.py index 2832d50..71203ef 100644 --- a/examples/bb144_deg5_tableau.py +++ b/examples/bb144_deg5_tableau.py @@ -2,12 +2,10 @@ from __future__ import annotations import argparse -from typing import List import stim - -from acid.codes.bb.builder_hexconn import get_spec from acid.codes.bb import builder_deg5 as deg5 +from acid.codes.bb.builder_hexconn import get_spec from acid.defects.defective_code import DefectiveCode from acid.tableau_visualiser.visualiser import TableauVisualiser @@ -15,7 +13,7 @@ def run(layers: int = 5, solve_time: float = 60.0, ticks: int = 30) -> None: # 1) Build bb 144 code with degree-5 connectivity (no defects) spec = get_spec("bb144") - base, embedding, _ = deg5.build_code_from_spec(spec) + base, _embedding, _ = deg5.build_code_from_spec(spec) print(f"Built code 'bb144' (deg5): n={base.num_qubits}, shapes={len(base.shapes)}") # 2) No dropouts @@ -31,7 +29,11 @@ def run(layers: int = 5, solve_time: float = 60.0, ticks: int = 30) -> None: anticommuting = circuit.anticommuting_bases() # 5) Visualise first `ticks` TICKs in the tableau - vis = TableauVisualiser(stim.Circuit(circ_text), commuting_bases=commuting, anticommuting_bases=anticommuting) + vis = TableauVisualiser( + stim.Circuit(circ_text), + commuting_bases=commuting, + anticommuting_bases=anticommuting, + ) snap = vis.snapshot() print(snap.to_ansi()) stepped = 0 @@ -42,10 +44,21 @@ def run(layers: int = 5, solve_time: float = 60.0, ticks: int = 30) -> None: def main() -> int: - ap = argparse.ArgumentParser(description="bb 144 (deg5) tableau: print first ticks of compiled schedule") - ap.add_argument("--layers", type=int, default=5, help="Schedule layers L (default: 5)") - ap.add_argument("--solve-time", type=float, default=60.0, help="Solver time limit in seconds (default: 60)") - ap.add_argument("--ticks", type=int, default=30, help="Number of TICKs to print (default: 30)") + ap = argparse.ArgumentParser( + description="bb 144 (deg5) tableau: print first ticks of compiled schedule" + ) + ap.add_argument( + "--layers", type=int, default=5, help="Schedule layers L (default: 5)" + ) + ap.add_argument( + "--solve-time", + type=float, + default=60.0, + help="Solver time limit in seconds (default: 60)", + ) + ap.add_argument( + "--ticks", type=int, default=30, help="Number of TICKs to print (default: 30)" + ) args = ap.parse_args() run(layers=args.layers, solve_time=args.solve_time, ticks=args.ticks) return 0 @@ -53,4 +66,3 @@ def main() -> int: if __name__ == "__main__": raise SystemExit(main()) - diff --git a/examples/bb_144_deg5.py b/examples/bb_144_deg5.py index ce8fcac..9528805 100644 --- a/examples/bb_144_deg5.py +++ b/examples/bb_144_deg5.py @@ -2,13 +2,12 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path -from acid.codes.bb.builder_hexconn import get_spec from acid.codes.bb import builder_deg5 as deg5 +from acid.codes.bb.builder_hexconn import get_spec from acid.defects.defective_code import DefectiveCode from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -35,51 +34,66 @@ def run( uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v, _cls) in connections}) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + def parse_qubits(s: str | None) -> list[int]: if not s: return [] parts = [p for p in re.split(r"[\s,]+", s.strip()) if p] - return sorted(list({int(p) for p in parts})) + return sorted({int(p) for p in parts}) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) print("Stats:") for k in sorted(dcode.stats().keys()): print(f" {k}: {dcode.stats()[k]}") @@ -101,7 +115,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -125,17 +144,41 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="BB bb144 (deg5): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="BB bb144 (deg5): compile and emit memory experiment" + ) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/bb_144_hex.py b/examples/bb_144_hex.py index 1769283..975805e 100644 --- a/examples/bb_144_hex.py +++ b/examples/bb_144_hex.py @@ -2,12 +2,11 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path -from acid.codes.bb.builder_hexconn import get_spec, build_code_from_spec +from acid.codes.bb.builder_hexconn import build_code_from_spec, get_spec from acid.defects.defective_code import DefectiveCode from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -34,51 +33,69 @@ def run( uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v, _cls) in connections}) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + def parse_qubits(s: str | None) -> list[int]: if not s: return [] parts = [p for p in re.split(r"[\s,]+", s.strip()) if p] - return sorted(list({int(p) for p in parts})) + return sorted({int(p) for p in parts}) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: + # randomly drop qubits nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: + # randomly drop couplers nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + # create defective code with dropped qubits and couplers + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) print("Stats:") for k in sorted(dcode.stats().keys()): print(f" {k}: {dcode.stats()[k]}") @@ -100,7 +117,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -124,17 +146,41 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="BB bb144 (hex): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="BB bb144 (hex): compile and emit memory experiment" + ) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/bb_288_deg5.py b/examples/bb_288_deg5.py index c79fd45..dcb842d 100644 --- a/examples/bb_288_deg5.py +++ b/examples/bb_288_deg5.py @@ -2,13 +2,12 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path -from acid.codes.bb.builder_hexconn import get_spec from acid.codes.bb import builder_deg5 as deg5 +from acid.codes.bb.builder_hexconn import get_spec from acid.defects.defective_code import DefectiveCode from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -35,51 +34,66 @@ def run( uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v, _cls) in connections}) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + def parse_qubits(s: str | None) -> list[int]: if not s: return [] parts = [p for p in re.split(r"[\s,]+", s.strip()) if p] - return sorted(list({int(p) for p in parts})) + return sorted({int(p) for p in parts}) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) print("Stats:") for k in sorted(dcode.stats().keys()): print(f" {k}: {dcode.stats()[k]}") @@ -101,7 +115,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -125,17 +144,41 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="BB bb288 (deg5): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="BB bb288 (deg5): compile and emit memory experiment" + ) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/bb_288_hex.py b/examples/bb_288_hex.py index 69a9a3d..e1406a0 100644 --- a/examples/bb_288_hex.py +++ b/examples/bb_288_hex.py @@ -2,12 +2,11 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path -from acid.codes.bb.builder_hexconn import get_spec, build_code_from_spec +from acid.codes.bb.builder_hexconn import build_code_from_spec, get_spec from acid.defects.defective_code import DefectiveCode from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -29,34 +28,37 @@ def run( key = "bb288" spec = get_spec(key) base, embedding, connections = build_code_from_spec(spec) - print(f"Built base code '{key}' (hex): n={base.num_qubits}, shapes={len(base.shapes)}") + print( + f"Built base code '{key}' (hex): n={base.num_qubits}, shapes={len(base.shapes)}" + ) # 2) Select dropped qubits and couplers (explicit lists override random counts) uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v, _cls) in connections}) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + def parse_qubits(s: str | None) -> list[int]: if not s: return [] parts = [p for p in re.split(r"[\s,]+", s.strip()) if p] - out: List[int] = [] + out: list[int] = [] for p in parts: out.append(int(p)) - return sorted(list({q for q in out})) + return sorted({q for q in out}) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] pairs = [p for p in re.split(r"[\s,]+", s.strip()) if p] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in pairs: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) # Note: the CLI parsing for explicit lists is added below in main(); here we expect # to be called with either explicit lists parsed in or counts provided. @@ -67,32 +69,46 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") # 3) Defective code and stats - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) stats = dcode.stats() print("Stats:") for k in sorted(stats.keys()): @@ -113,12 +129,19 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: print(f" L={L_try} failed: {e}", flush=True) continue if circuit is None: - raise SystemExit("No feasible schedule found for L in [2..6]. Try increasing solve time.") + raise SystemExit( + "No feasible schedule found for L in [2..6]. Try increasing solve time." + ) counts = [len(layer.chosen) for layer in circuit.layers] print(f"Layered schedule chosen counts: {counts}") # 5) Emit a full memory experiment with R rounds (detectors, observables optional) - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -142,17 +165,41 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="BB bb288 (hex): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="BB bb288 (hex): compile and emit memory experiment" + ) ap.add_argument("--solve-time", type=float, default=30.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=1, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/colour_hex_d3.py b/examples/colour_hex_d3.py index 6dcbd58..aacecd4 100644 --- a/examples/colour_hex_d3.py +++ b/examples/colour_hex_d3.py @@ -2,14 +2,13 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path from acid.codes.colour.hex import build_colour_hex_code -from acid.embedding import CoordMapEmbedding from acid.defects.defective_code import DefectiveCode +from acid.embedding import CoordMapEmbedding from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -29,53 +28,75 @@ def run( ) -> None: base, coords = build_colour_hex_code(int(distance), deg4=False) embedding = CoordMapEmbedding(coords) - print(f"Built colour code (hex, degree-3), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}") + print( + f"Built colour code (hex, degree-3), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}" + ) # Dropouts (explicit lists override random counts) - uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()}) + uniq_edges = sorted( + {(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()} + ) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + + def parse_qubits(s: str | None) -> list[int]: if not s: return [] - return sorted(list({int(p) for p in re.split(r"[\s,]+", s.strip()) if p})) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + return sorted({int(p) for p in re.split(r"[\s,]+", s.strip()) if p}) + + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) + explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) print("Stats:") for k in sorted(dcode.stats().keys()): print(f" {k}: {dcode.stats()[k]}") @@ -97,7 +118,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -119,18 +145,42 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="Colour code (hex degree-3): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="Colour code (hex degree-3): compile and emit memory experiment" + ) ap.add_argument("--distance", type=int, default=7) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/colour_square_deg4.py b/examples/colour_square_deg4.py index ab427dd..59a9543 100644 --- a/examples/colour_square_deg4.py +++ b/examples/colour_square_deg4.py @@ -2,14 +2,14 @@ from __future__ import annotations import argparse -from pathlib import Path import os -from typing import List, Tuple import random +import re +from pathlib import Path from acid.codes.colour.hex import build_colour_hex_code -from acid.embedding import CoordMapEmbedding from acid.defects.defective_code import DefectiveCode +from acid.embedding import CoordMapEmbedding from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -30,63 +30,93 @@ def run( drop_couplers: str | None = None, ) -> None: # Heads-up for users: this case can be heavy without pruning - print("[warning] Square ancilla-free (deg4) colour can take a while. Pruning is enabled by default (M=20).", flush=True) + print( + "[warning] Square ancilla-free (deg4) colour can take a while. Pruning is enabled by default (M=20).", + flush=True, + ) if verbose: os.environ["FAB_SCHEDULE_ENUM_VERBOSE"] = "1" os.environ["FAB_SCHEDULE_BUILD_VERBOSE"] = "1" # Square-grid ancilla-free colour code via deg4 hex builder (extra rung per hex) base, coords = build_colour_hex_code(int(distance), deg4=True) embedding = CoordMapEmbedding(coords) - print(f"Built colour code (square ancilla-free, deg4), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}") + print( + f"Built colour code (square ancilla-free, deg4), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}" + ) # Dropouts (explicit lists override random counts) - uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()}) + uniq_edges = sorted( + {(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()} + ) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + + def parse_qubits(s: str | None) -> list[int]: if not s: return [] - return sorted(list({int(p) for p in re.split(r"[\s,]+", s.strip()) if p})) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + return sorted({int(p) for p in re.split(r"[\s,]+", s.strip()) if p}) + + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) + explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) # Enable pruning by default for deg4 colour (default M=20) try: - dcode.prepare_solver(prune_params={"M": int(kept_schedules_per_quasi_stabilisers), "verbose": True}) + dcode.prepare_solver( + prune_params={ + "M": int(kept_schedules_per_quasi_stabilisers), + "verbose": True, + } + ) except Exception as e: print(f"[warn] pruning setup failed: {e}") print("Stats:") @@ -110,7 +140,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -132,20 +167,53 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="Colour code (square ancilla-free, deg4): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="Colour code (square ancilla-free, deg4): compile and emit memory experiment" + ) ap.add_argument("--distance", type=int, default=7) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=2, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=4, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--kept-schedules-per-quasi-stabilisers", type=int, default=20, help="Pruning: keep at most M schedules per quasi-stabiliser (default: 20)") - ap.add_argument("--verbose", action="store_true", help="Enable verbose schedule enumeration/build with tqdm progress") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--kept-schedules-per-quasi-stabilisers", + type=int, + default=20, + help="Pruning: keep at most M schedules per quasi-stabiliser (default: 20)", + ) + ap.add_argument( + "--verbose", + action="store_true", + help="Enable verbose schedule enumeration/build with tqdm progress", + ) + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/colour_square_superdense.py b/examples/colour_square_superdense.py index 2a750f4..dbc7dff 100644 --- a/examples/colour_square_superdense.py +++ b/examples/colour_square_superdense.py @@ -2,15 +2,14 @@ from __future__ import annotations import argparse -from pathlib import Path import os -from typing import List, Tuple import random import re +from pathlib import Path from acid.codes.colour.square import build_colour_square_code -from acid.embedding import CoordMapEmbedding from acid.defects.defective_code import DefectiveCode +from acid.embedding import CoordMapEmbedding from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -30,62 +29,92 @@ def run( drop_qubits: str | None = None, drop_couplers: str | None = None, ) -> None: - print("[warning] Superdense colour code can take a while to enumerate schedules and solve. Pruning is enabled by default (M=15).", flush=True) + print( + "[warning] Superdense colour code can take a while to enumerate schedules and solve. Pruning is enabled by default (M=15).", + flush=True, + ) if verbose: os.environ["FAB_SCHEDULE_ENUM_VERBOSE"] = "1" os.environ["FAB_SCHEDULE_BUILD_VERBOSE"] = "1" base, coords = build_colour_square_code(int(distance)) embedding = CoordMapEmbedding(coords) - print(f"Built colour code (superdense, square grid), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}") + print( + f"Built colour code (superdense, square grid), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}" + ) # Dropouts (explicit lists override random counts) - uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()}) + uniq_edges = sorted( + {(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()} + ) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + + def parse_qubits(s: str | None) -> list[int]: if not s: return [] - return sorted(list({int(p) for p in re.split(r"[\s,]+", s.strip()) if p})) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + return sorted({int(p) for p in re.split(r"[\s,]+", s.strip()) if p}) + + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) + explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) # Enable pruning by default for superdense colour (default M=15) try: - dcode.prepare_solver(prune_params={"M": int(kept_schedules_per_quasi_stabilisers), "verbose": True}) + dcode.prepare_solver( + prune_params={ + "M": int(kept_schedules_per_quasi_stabilisers), + "verbose": True, + } + ) except Exception as e: print(f"[warn] pruning setup failed: {e}") print("Stats:") @@ -109,7 +138,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -131,20 +165,53 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="Colour code (superdense, square grid): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="Colour code (superdense, square grid): compile and emit memory experiment" + ) ap.add_argument("--distance", type=int, default=7) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--kept-schedules-per-quasi-stabilisers", type=int, default=15, help="Pruning: keep at most M schedules per quasi-stabiliser (default: 15)") - ap.add_argument("--verbose", action="store_true", help="Enable verbose schedule enumeration/build with tqdm progress") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--kept-schedules-per-quasi-stabilisers", + type=int, + default=15, + help="Pruning: keep at most M schedules per quasi-stabiliser (default: 15)", + ) + ap.add_argument( + "--verbose", + action="store_true", + help="Enable verbose schedule enumeration/build with tqdm progress", + ) + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/surface_unrotated_grid.py b/examples/surface_unrotated_grid.py index 9d7fa3f..3a67fa6 100644 --- a/examples/surface_unrotated_grid.py +++ b/examples/surface_unrotated_grid.py @@ -2,14 +2,15 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path -from acid.codes.surface.unrotated_grid_square_edges import build_unrotated_surface_grid_square_edges_code as build_surface_square_edges -from acid.embedding import CoordMapEmbedding +from acid.codes.surface.unrotated_grid_square_edges import ( + build_unrotated_surface_grid_square_edges_code as build_surface_square_edges, +) from acid.defects.defective_code import DefectiveCode +from acid.embedding import CoordMapEmbedding from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -30,53 +31,75 @@ def run( # Surface code on a square grid with square edges to the boundary (includes boundary singles) base, coords = build_surface_square_edges(int(distance)) embedding = CoordMapEmbedding(coords) - print(f"Built surface (square edges with boundary singles), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}") + print( + f"Built surface (square edges with boundary singles), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}" + ) # Dropouts (explicit lists override random counts) - uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()}) + uniq_edges = sorted( + {(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()} + ) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + + def parse_qubits(s: str | None) -> list[int]: if not s: return [] - return sorted(list({int(p) for p in re.split(r"[\s,]+", s.strip()) if p})) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + return sorted({int(p) for p in re.split(r"[\s,]+", s.strip()) if p}) + + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) + explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) print("Stats:") for k in sorted(dcode.stats().keys()): print(f" {k}: {dcode.stats()[k]}") @@ -98,7 +121,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -120,18 +148,42 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="Unrotated surface (grid): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="Unrotated surface (grid): compile and emit memory experiment" + ) ap.add_argument("--distance", type=int, default=7) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/examples/surface_unrotated_hex.py b/examples/surface_unrotated_hex.py index e5a71f2..c9bd4af 100644 --- a/examples/surface_unrotated_hex.py +++ b/examples/surface_unrotated_hex.py @@ -2,14 +2,13 @@ from __future__ import annotations import argparse -from pathlib import Path -from typing import List, Tuple import random import re +from pathlib import Path from acid.codes.surface.unrotated_hex import build_unrotated_surface_hex_code -from acid.embedding import CoordMapEmbedding from acid.defects.defective_code import DefectiveCode +from acid.embedding import CoordMapEmbedding from acid.memory_experiment.experiment import MemoryExperiment, MemoryExperimentConfig from acid.stim_to_shatter_url import prompt_open_shatter @@ -29,53 +28,75 @@ def run( ) -> None: base, coords = build_unrotated_surface_hex_code(int(distance)) embedding = CoordMapEmbedding(coords) - print(f"Built unrotated surface (hex), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}") + print( + f"Built unrotated surface (hex), d={distance}: n={base.num_qubits}, shapes={len(base.shapes)}" + ) # Dropouts (explicit lists override random counts) - uniq_edges = sorted({(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()}) + uniq_edges = sorted( + {(min(u, v), max(u, v)) for (u, v) in base.connectivity_graph.edges()} + ) all_qubits = list(range(base.num_qubits)) - def parse_qubits(s: str | None) -> List[int]: + + def parse_qubits(s: str | None) -> list[int]: if not s: return [] - return sorted(list({int(p) for p in re.split(r"[\s,]+", s.strip()) if p})) - def parse_couplers(s: str | None) -> List[Tuple[int, int]]: + return sorted({int(p) for p in re.split(r"[\s,]+", s.strip()) if p}) + + def parse_couplers(s: str | None) -> list[tuple[int, int]]: if not s: return [] - out: List[Tuple[int, int]] = [] + out: list[tuple[int, int]] = [] for token in [p for p in re.split(r"[\s,]+", s.strip()) if p]: - if '-' not in token: + if "-" not in token: raise ValueError(f"Invalid coupler token '{token}'. Use 'u-v'.") - a_s, b_s = token.split('-', 1) - a = int(a_s); b = int(b_s) + a_s, b_s = token.split("-", 1) + a = int(a_s) + b = int(b_s) u, v = (a, b) if a <= b else (b, a) out.append((u, v)) - return sorted(list({t for t in out})) + return sorted({t for t in out}) + explicit_qubits = parse_qubits(drop_qubits) explicit_couplers = parse_couplers(drop_couplers) if explicit_qubits and n_dropped_qubits: - raise SystemExit("Specify either --n-dropped-qubits or --drop-qubits, not both.") + raise SystemExit( + "Specify either --n-dropped-qubits or --drop-qubits, not both." + ) if explicit_couplers and n_dropped_couplers: - raise SystemExit("Specify either --n-dropped-couplers or --drop-couplers, not both.") + raise SystemExit( + "Specify either --n-dropped-couplers or --drop-couplers, not both." + ) if explicit_qubits: for q in explicit_qubits: if q not in all_qubits: - raise SystemExit(f"Dropped qubit {q} out of range [0..{base.num_qubits-1}]") - dropped_nodes: List[int] = explicit_qubits + raise SystemExit( + f"Dropped qubit {q} out of range [0..{base.num_qubits - 1}]" + ) + dropped_nodes: list[int] = explicit_qubits else: nQ = max(0, int(n_dropped_qubits)) - dropped_nodes = random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + dropped_nodes = ( + random.sample(all_qubits, min(nQ, len(all_qubits))) if nQ > 0 else [] + ) if explicit_couplers: valid = set(uniq_edges) for e in explicit_couplers: if e not in valid: - raise SystemExit(f"Dropped coupler {e[0]}-{e[1]} not in device connectivity") - dropped_edges: List[Tuple[int, int]] = explicit_couplers + raise SystemExit( + f"Dropped coupler {e[0]}-{e[1]} not in device connectivity" + ) + dropped_edges: list[tuple[int, int]] = explicit_couplers else: nE = max(0, int(n_dropped_couplers)) - dropped_edges = random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + dropped_edges = ( + random.sample(uniq_edges, min(nE, len(uniq_edges))) if nE > 0 else [] + ) print(f"Dropouts: nodes={dropped_nodes} edges={dropped_edges}") - dcode = DefectiveCode(base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges) + dcode = DefectiveCode( + base, dropped_nodes=dropped_nodes, dropped_edges=dropped_edges + ) print("Stats:") for k in sorted(dcode.stats().keys()): print(f" {k}: {dcode.stats()[k]}") @@ -97,7 +118,12 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: raise SystemExit("No feasible schedule found for L in [2..6].") # Memory experiment - exp = MemoryExperiment(dcode=dcode, circuit=circuit, embedding=embedding, cfg=MemoryExperimentConfig(R=int(rounds))) + exp = MemoryExperiment( + dcode=dcode, + circuit=circuit, + embedding=embedding, + cfg=MemoryExperimentConfig(R=int(rounds)), + ) stim_text = exp.build( include_x_detectors=bool(output_detectors_and_observables), include_z_detectors=bool(output_detectors_and_observables), @@ -119,18 +145,42 @@ def parse_couplers(s: str | None) -> List[Tuple[int, int]]: def main() -> int: - ap = argparse.ArgumentParser(description="Unrotated surface (hex): compile and emit memory experiment") + ap = argparse.ArgumentParser( + description="Unrotated surface (hex): compile and emit memory experiment" + ) ap.add_argument("--distance", type=int, default=7) ap.add_argument("--solve-time", type=float, default=60.0) ap.add_argument("--rounds", type=int, default=1) ap.add_argument("--out", type=str) - ap.add_argument("--n-dropped-qubits", type=int, default=0, help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)") - ap.add_argument("--n-dropped-couplers", type=int, default=0, help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)") - ap.add_argument("--drop-qubits", type=str, help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')") - ap.add_argument("--drop-couplers", type=str, help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')") + ap.add_argument( + "--n-dropped-qubits", + type=int, + default=0, + help="Number of randomly dropped qubits (mutually exclusive with --drop-qubits)", + ) + ap.add_argument( + "--n-dropped-couplers", + type=int, + default=0, + help="Number of randomly dropped couplers (mutually exclusive with --drop-couplers)", + ) + ap.add_argument( + "--drop-qubits", + type=str, + help="Comma/space-separated list of qubit ids to drop (e.g. '1,2,5')", + ) + ap.add_argument( + "--drop-couplers", + type=str, + help="Comma/space-separated list of couplers 'u-v' to drop (e.g. '1-7,3-8')", + ) ap.add_argument("--output-state-prep", action="store_true") ap.add_argument("--output-detectors-and-observables", action="store_true") - ap.add_argument("--no-web-prompt", action="store_true", help="Do not prompt to open Shatter in a browser") + ap.add_argument( + "--no-web-prompt", + action="store_true", + help="Do not prompt to open Shatter in a browser", + ) args = ap.parse_args() if args.output_detectors_and_observables and not args.output_state_prep: ap.error("--output-detectors-and-observables requires --output-state-prep") diff --git a/ACID/pyproject.toml b/pyproject.toml similarity index 91% rename from ACID/pyproject.toml rename to pyproject.toml index ac94350..528ec62 100644 --- a/ACID/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,10 @@ dependencies = [ ] [project.optional-dependencies] -# No optional extras required currently. +dev = [ + "ruff", + "ty", +] [project.urls] Homepage = "https://example.org" @@ -29,4 +32,4 @@ Homepage = "https://example.org" acid-tableau = "acid.tableau_visualiser.cli:main" [tool.setuptools.packages.find] -where = ["src"] +where = ["ACID/src"] diff --git a/visualisations/bb_144_hex_dropQ0_dropE0_L2_R1.stim b/visualisations/bb_144_hex_dropQ0_dropE0_L2_R1.stim index 3e7176c..6aaba80 100644 --- a/visualisations/bb_144_hex_dropQ0_dropE0_L2_R1.stim +++ b/visualisations/bb_144_hex_dropQ0_dropE0_L2_R1.stim @@ -600,39 +600,39 @@ QUBIT_COORDS(11.5, 5) 143 #!pragma POLYGON(0,0,1,0.15) 8 143 140 141 97 14 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 10 142 143 133 99 16 -CX 18 133 57 88 39 82 86 69 114 85 53 84 111 10 139 26 4 131 125 12 14 141 71 102 100 83 81 112 128 99 110 93 32 3 96 79 0 127 135 34 67 98 121 20 25 68 77 108 142 113 124 107 46 17 95 126 91 122 138 109 49 92 28 11 105 136 63 106 56 27 120 103 42 13 24 7 73 116 101 132 5 36 23 54 52 35 70 41 9 40 80 51 119 6 38 21 66 37 87 130 134 117 19 50 1 44 48 31 22 137 94 65 97 140 8 123 47 78 76 59 33 64 15 58 143 30 62 45 72 55 129 16 90 61 115 2 43 74 118 89 29 60 104 75 +CX 20 11 17 46 45 62 52 43 84 75 88 79 116 107 13 42 141 14 48 39 112 103 105 122 80 71 109 138 41 70 69 86 76 67 73 102 140 131 9 26 16 7 8 143 101 130 72 63 5 34 136 127 97 126 113 142 137 22 1 30 44 35 65 94 12 3 93 110 108 99 37 66 33 50 133 18 40 31 104 95 129 2 100 91 4 139 68 59 132 123 36 27 0 135 128 119 61 90 32 23 29 58 57 74 64 55 96 87 89 118 117 134 60 51 124 115 53 82 81 98 85 114 125 10 25 54 21 38 121 6 28 19 92 83 56 47 77 106 120 111 24 15 49 78 TICK -CX 141 8 55 66 98 101 41 52 20 23 59 70 84 87 116 119 34 25 126 129 130 121 51 62 69 80 112 115 2 5 122 125 140 143 137 4 65 76 83 94 30 33 58 49 37 48 16 19 93 104 136 139 133 0 79 90 26 29 44 47 108 111 12 15 109 120 107 118 61 72 40 43 45 56 103 114 36 39 89 100 68 71 132 135 11 22 54 57 82 73 75 86 85 96 131 142 117 128 88 91 64 67 7 18 50 53 99 110 60 63 3 14 35 46 78 81 106 97 127 138 21 32 10 1 31 42 74 77 17 28 113 124 92 95 123 134 102 105 27 38 6 9 13 24 +CX 34 117 139 136 98 37 43 40 107 104 30 113 70 9 134 73 103 100 126 65 135 132 58 141 39 36 26 109 131 128 66 5 130 69 11 8 75 72 122 61 62 1 7 4 94 33 71 68 22 105 35 32 99 96 3 0 90 29 54 137 67 64 127 124 86 25 31 28 118 57 95 92 18 101 50 133 114 53 123 120 46 129 27 24 91 88 14 97 63 60 110 49 55 52 119 116 59 56 82 21 10 93 51 48 79 76 6 89 87 84 143 140 78 17 42 125 23 20 142 81 74 13 138 77 19 16 106 45 83 80 115 112 38 121 111 108 102 41 47 44 15 12 2 85 TICK -CX 47 56 20 11 84 75 93 102 15 24 33 42 79 88 126 117 130 109 112 103 43 52 107 116 125 134 29 38 66 57 94 73 140 131 61 82 39 48 58 37 62 53 8 143 22 1 7 16 71 80 90 81 118 97 108 99 35 44 21 30 3 12 25 46 40 31 67 76 77 86 104 95 100 91 4 139 127 136 68 59 113 122 132 123 17 26 54 45 10 133 110 101 128 119 49 70 0 135 96 87 18 9 27 36 64 55 50 41 142 121 141 6 63 72 13 34 14 5 106 85 105 114 51 60 138 129 69 78 28 19 23 32 115 124 65 74 2 137 83 92 120 111 98 89 +CX 11 42 57 88 53 84 111 10 139 26 120 89 125 12 7 38 71 102 81 112 98 67 35 66 135 34 134 103 80 37 21 52 126 95 25 68 130 87 77 108 99 142 131 18 31 62 48 17 122 91 49 92 45 76 27 70 55 86 141 28 58 15 13 56 127 14 44 1 105 136 118 75 59 90 41 72 104 61 32 133 73 116 101 132 23 54 60 29 51 94 123 22 9 40 109 8 119 6 65 96 4 117 114 83 137 24 19 50 36 5 0 113 82 39 110 79 100 69 128 85 97 140 64 33 143 30 107 138 124 93 129 16 46 3 115 2 43 74 78 47 106 63 20 121 TICK -MX 2 3 7 10 13 17 20 21 27 35 40 50 51 54 58 61 64 65 68 69 79 83 84 93 98 106 107 108 112 113 126 127 130 132 140 141 -MZ 1 5 9 19 24 32 38 42 46 48 52 53 56 57 70 72 73 76 80 81 86 87 91 95 97 101 111 114 119 121 124 129 134 135 139 143 +MX 7 11 19 23 27 31 35 43 46 51 55 58 59 71 78 82 98 99 106 107 110 111 114 115 118 119 122 123 126 127 130 131 134 135 139 143 +MZ 1 5 8 12 16 17 24 28 29 33 37 40 52 56 61 68 69 72 76 84 85 88 89 92 93 96 108 112 113 116 117 121 132 133 136 140 TICK -RX 2 3 7 10 13 17 20 21 27 35 40 50 51 54 58 61 64 65 68 69 79 83 84 93 98 106 107 108 112 113 126 127 130 132 140 141 -R 1 5 9 19 24 32 38 42 46 48 52 53 56 57 70 72 73 76 80 81 86 87 91 95 97 101 111 114 119 121 124 129 134 135 139 143 +RX 7 11 19 23 27 31 35 43 46 51 55 58 59 71 78 82 98 99 106 107 110 111 114 115 118 119 122 123 126 127 130 131 134 135 139 143 +R 1 5 8 12 16 17 24 28 29 33 37 40 52 56 61 68 69 72 76 84 85 88 89 92 93 96 108 112 113 116 117 121 132 133 136 140 TICK -CX 47 56 20 11 84 75 93 102 15 24 33 42 79 88 126 117 130 109 112 103 43 52 107 116 125 134 29 38 66 57 94 73 140 131 61 82 39 48 58 37 62 53 8 143 22 1 7 16 71 80 90 81 118 97 108 99 35 44 21 30 3 12 25 46 40 31 67 76 77 86 104 95 100 91 4 139 127 136 68 59 113 122 132 123 17 26 54 45 10 133 110 101 128 119 49 70 0 135 96 87 18 9 27 36 64 55 50 41 142 121 141 6 63 72 13 34 14 5 106 85 105 114 51 60 138 129 69 78 28 19 23 32 115 124 65 74 2 137 83 92 120 111 98 89 +CX 11 42 57 88 53 84 111 10 139 26 120 89 125 12 7 38 71 102 81 112 98 67 35 66 135 34 134 103 80 37 21 52 126 95 25 68 130 87 77 108 99 142 131 18 31 62 48 17 122 91 49 92 45 76 27 70 55 86 141 28 58 15 13 56 127 14 44 1 105 136 118 75 59 90 41 72 104 61 32 133 73 116 101 132 23 54 60 29 51 94 123 22 9 40 109 8 119 6 65 96 4 117 114 83 137 24 19 50 36 5 0 113 82 39 110 79 100 69 128 85 97 140 64 33 143 30 107 138 124 93 129 16 46 3 115 2 43 74 78 47 106 63 20 121 TICK -CX 141 8 55 66 98 101 41 52 20 23 59 70 84 87 116 119 34 25 126 129 130 121 51 62 69 80 112 115 2 5 122 125 140 143 137 4 65 76 83 94 30 33 58 49 37 48 16 19 93 104 136 139 133 0 79 90 26 29 44 47 108 111 12 15 109 120 107 118 61 72 40 43 45 56 103 114 36 39 89 100 68 71 132 135 11 22 54 57 82 73 75 86 85 96 131 142 117 128 88 91 64 67 7 18 50 53 99 110 60 63 3 14 35 46 78 81 106 97 127 138 21 32 10 1 31 42 74 77 17 28 113 124 92 95 123 134 102 105 27 38 6 9 13 24 +CX 34 117 139 136 98 37 43 40 107 104 30 113 70 9 134 73 103 100 126 65 135 132 58 141 39 36 26 109 131 128 66 5 130 69 11 8 75 72 122 61 62 1 7 4 94 33 71 68 22 105 35 32 99 96 3 0 90 29 54 137 67 64 127 124 86 25 31 28 118 57 95 92 18 101 50 133 114 53 123 120 46 129 27 24 91 88 14 97 63 60 110 49 55 52 119 116 59 56 82 21 10 93 51 48 79 76 6 89 87 84 143 140 78 17 42 125 23 20 142 81 74 13 138 77 19 16 106 45 83 80 115 112 38 121 111 108 102 41 47 44 15 12 2 85 TICK -CX 18 133 57 88 39 82 86 69 114 85 53 84 111 10 139 26 4 131 125 12 14 141 71 102 100 83 81 112 128 99 110 93 32 3 96 79 0 127 135 34 67 98 121 20 25 68 77 108 142 113 124 107 46 17 95 126 91 122 138 109 49 92 28 11 105 136 63 106 56 27 120 103 42 13 24 7 73 116 101 132 5 36 23 54 52 35 70 41 9 40 80 51 119 6 38 21 66 37 87 130 134 117 19 50 1 44 48 31 22 137 94 65 97 140 8 123 47 78 76 59 33 64 15 58 143 30 62 45 72 55 129 16 90 61 115 2 43 74 118 89 29 60 104 75 +CX 20 11 17 46 45 62 52 43 84 75 88 79 116 107 13 42 141 14 48 39 112 103 105 122 80 71 109 138 41 70 69 86 76 67 73 102 140 131 9 26 16 7 8 143 101 130 72 63 5 34 136 127 97 126 113 142 137 22 1 30 44 35 65 94 12 3 93 110 108 99 37 66 33 50 133 18 40 31 104 95 129 2 100 91 4 139 68 59 132 123 36 27 0 135 128 119 61 90 32 23 29 58 57 74 64 55 96 87 89 118 117 134 60 51 124 115 53 82 81 98 85 114 125 10 25 54 21 38 121 6 28 19 92 83 56 47 77 106 120 111 24 15 49 78 TICK -CX 11 42 40 23 68 39 54 25 75 118 132 115 7 38 36 19 10 125 85 128 35 66 82 53 64 47 21 52 131 18 50 33 6 121 78 49 117 4 99 142 3 46 31 62 60 43 106 77 17 48 92 63 20 135 45 76 27 70 55 86 74 57 102 73 13 56 141 28 127 14 113 0 41 72 59 90 88 71 116 87 98 81 2 129 69 100 123 22 51 94 126 97 108 91 109 8 84 67 65 96 130 101 16 143 34 5 137 24 83 114 112 95 12 139 93 124 122 105 140 111 79 110 37 80 30 1 133 32 107 138 136 119 58 29 44 15 26 9 103 134 61 104 89 120 +CX 134 125 27 56 55 72 126 117 38 29 130 109 119 136 127 0 34 13 63 92 59 76 66 57 94 73 122 113 23 40 30 21 123 8 58 37 51 80 62 53 87 116 115 132 22 1 19 36 26 17 90 81 83 100 118 97 79 96 86 77 47 64 143 16 15 44 114 105 107 124 111 140 43 60 54 45 82 61 10 133 110 101 103 120 11 28 18 9 39 68 46 25 50 41 142 121 6 141 139 12 75 104 7 24 14 5 78 69 71 88 106 85 67 84 74 65 138 129 35 52 135 20 131 4 95 112 102 93 99 128 3 32 31 48 2 137 42 33 70 49 91 108 98 89 TICK -CX 63 74 24 27 42 45 70 61 73 84 119 130 105 116 52 55 134 137 101 112 38 41 5 16 48 51 80 83 23 34 66 69 94 85 87 98 9 20 76 79 97 108 1 12 19 30 62 65 115 126 129 140 47 58 72 75 111 122 15 26 33 44 143 10 22 13 90 93 118 109 43 54 86 89 125 136 29 40 8 11 104 107 114 117 39 50 57 68 100 103 121 132 139 6 110 113 128 131 53 64 32 35 71 82 96 99 18 21 46 37 25 36 4 7 135 2 81 92 124 127 142 133 67 78 14 17 120 123 0 3 77 88 95 106 138 141 49 60 28 31 91 102 56 59 +CX 120 71 125 122 29 26 116 55 16 99 61 70 84 35 112 51 57 54 80 19 44 127 89 86 76 15 140 79 121 130 53 50 117 114 40 123 12 107 85 94 8 91 136 75 81 78 25 34 72 23 77 74 141 138 21 18 32 115 108 59 36 131 113 110 17 14 104 43 100 39 4 87 45 42 68 7 49 58 128 67 109 118 132 83 137 134 13 22 41 38 64 3 28 111 105 102 0 95 73 82 101 98 96 47 124 63 5 2 69 66 56 139 60 11 129 126 133 142 9 6 20 103 65 62 24 119 52 135 92 31 97 106 1 10 93 90 88 27 33 30 37 46 48 143 TICK -CX 47 56 84 75 93 102 111 120 15 24 33 42 37 58 116 107 38 29 126 117 130 109 48 39 133 10 34 13 43 52 80 71 125 134 94 73 103 112 122 113 61 82 30 21 57 66 131 140 16 7 8 143 62 53 11 20 72 63 121 142 44 35 108 99 12 3 85 106 135 0 81 90 40 31 67 76 25 46 77 86 104 95 127 136 100 91 4 139 132 123 17 26 36 27 128 119 49 70 32 23 96 87 45 54 64 55 141 6 60 51 41 50 59 68 105 114 101 110 5 14 69 78 28 19 92 83 129 138 115 124 9 18 65 74 2 137 88 79 97 118 98 89 1 22 +CX 57 88 74 43 56 13 120 89 102 71 7 38 42 11 81 112 98 67 2 115 84 53 70 27 135 34 52 21 80 37 134 103 30 143 77 108 130 87 99 142 117 4 16 129 26 139 31 62 95 126 66 35 94 51 17 48 140 97 12 125 91 122 49 92 76 45 55 86 72 41 141 28 105 136 127 14 44 1 63 106 90 59 113 0 118 75 32 133 73 116 101 132 123 22 68 25 9 40 109 8 119 6 18 131 114 83 137 24 19 50 36 5 54 23 10 111 100 69 82 39 128 85 79 110 96 65 47 78 64 33 15 58 107 138 124 93 46 3 60 29 20 121 61 104 TICK -MX 1 4 5 8 9 15 25 28 32 33 38 43 47 48 49 57 62 67 72 77 80 81 94 96 97 100 101 104 105 111 115 121 125 128 129 135 -MZ 3 6 7 10 13 20 21 26 27 31 35 50 51 54 55 58 68 74 75 78 79 82 83 89 99 102 106 107 109 112 113 117 123 136 137 140 +MX 9 12 16 17 20 32 36 44 49 52 56 57 60 61 64 68 72 73 76 77 80 81 84 96 100 101 105 109 113 117 120 124 128 137 140 141 +MZ 3 6 11 14 22 23 27 34 35 38 39 43 50 51 58 59 62 67 71 75 78 83 86 87 103 106 110 111 115 122 126 131 138 139 142 143 TICK -RX 1 4 5 8 9 15 25 28 32 33 38 43 47 48 49 57 62 67 72 77 80 81 94 96 97 100 101 104 105 111 115 121 125 128 129 135 -R 3 6 7 10 13 20 21 26 27 31 35 50 51 54 55 58 68 74 75 78 79 82 83 89 99 102 106 107 109 112 113 117 123 136 137 140 +RX 9 12 16 17 20 32 36 44 49 52 56 57 60 61 64 68 72 73 76 77 80 81 84 96 100 101 105 109 113 117 120 124 128 137 140 141 +R 3 6 11 14 22 23 27 34 35 38 39 43 50 51 58 59 62 67 71 75 78 83 86 87 103 106 110 111 115 122 126 131 138 139 142 143 TICK -CX 47 56 84 75 93 102 111 120 15 24 33 42 37 58 116 107 38 29 126 117 130 109 48 39 133 10 34 13 43 52 80 71 125 134 94 73 103 112 122 113 61 82 30 21 57 66 131 140 16 7 8 143 62 53 11 20 72 63 121 142 44 35 108 99 12 3 85 106 135 0 81 90 40 31 67 76 25 46 77 86 104 95 127 136 100 91 4 139 132 123 17 26 36 27 128 119 49 70 32 23 96 87 45 54 64 55 141 6 60 51 41 50 59 68 105 114 101 110 5 14 69 78 28 19 92 83 129 138 115 124 9 18 65 74 2 137 88 79 97 118 98 89 1 22 +CX 57 88 74 43 56 13 120 89 102 71 7 38 42 11 81 112 98 67 2 115 84 53 70 27 135 34 52 21 80 37 134 103 30 143 77 108 130 87 99 142 117 4 16 129 26 139 31 62 95 126 66 35 94 51 17 48 140 97 12 125 91 122 49 92 76 45 55 86 72 41 141 28 105 136 127 14 44 1 63 106 90 59 113 0 118 75 32 133 73 116 101 132 123 22 68 25 9 40 109 8 119 6 18 131 114 83 137 24 19 50 36 5 54 23 10 111 100 69 82 39 128 85 79 110 96 65 47 78 64 33 15 58 107 138 124 93 46 3 60 29 20 121 61 104 TICK -CX 63 74 24 27 42 45 70 61 73 84 119 130 105 116 52 55 134 137 101 112 38 41 5 16 48 51 80 83 23 34 66 69 94 85 87 98 9 20 76 79 97 108 1 12 19 30 62 65 115 126 129 140 47 58 72 75 111 122 15 26 33 44 143 10 22 13 90 93 118 109 43 54 86 89 125 136 29 40 8 11 104 107 114 117 39 50 57 68 100 103 121 132 139 6 110 113 128 131 53 64 32 35 71 82 96 99 18 21 46 37 25 36 4 7 135 2 81 92 124 127 142 133 67 78 14 17 120 123 0 3 77 88 95 106 138 141 49 60 28 31 91 102 56 59 +CX 120 71 125 122 29 26 116 55 16 99 61 70 84 35 112 51 57 54 80 19 44 127 89 86 76 15 140 79 121 130 53 50 117 114 40 123 12 107 85 94 8 91 136 75 81 78 25 34 72 23 77 74 141 138 21 18 32 115 108 59 36 131 113 110 17 14 104 43 100 39 4 87 45 42 68 7 49 58 128 67 109 118 132 83 137 134 13 22 41 38 64 3 28 111 105 102 0 95 73 82 101 98 96 47 124 63 5 2 69 66 56 139 60 11 129 126 133 142 9 6 20 103 65 62 24 119 52 135 92 31 97 106 1 10 93 90 88 27 33 30 37 46 48 143 TICK -CX 11 42 40 23 68 39 54 25 75 118 132 115 7 38 36 19 10 125 85 128 35 66 82 53 64 47 21 52 131 18 50 33 6 121 78 49 117 4 99 142 3 46 31 62 60 43 106 77 17 48 92 63 20 135 45 76 27 70 55 86 74 57 102 73 13 56 141 28 127 14 113 0 41 72 59 90 88 71 116 87 98 81 2 129 69 100 123 22 51 94 126 97 108 91 109 8 84 67 65 96 130 101 16 143 34 5 137 24 83 114 112 95 12 139 93 124 122 105 140 111 79 110 37 80 30 1 133 32 107 138 136 119 58 29 44 15 26 9 103 134 61 104 89 120 +CX 134 125 27 56 55 72 126 117 38 29 130 109 119 136 127 0 34 13 63 92 59 76 66 57 94 73 122 113 23 40 30 21 123 8 58 37 51 80 62 53 87 116 115 132 22 1 19 36 26 17 90 81 83 100 118 97 79 96 86 77 47 64 143 16 15 44 114 105 107 124 111 140 43 60 54 45 82 61 10 133 110 101 103 120 11 28 18 9 39 68 46 25 50 41 142 121 6 141 139 12 75 104 7 24 14 5 78 69 71 88 106 85 67 84 74 65 138 129 35 52 135 20 131 4 95 112 102 93 99 128 3 32 31 48 2 137 42 33 70 49 91 108 98 89 TICK diff --git a/visualisations/bb_288_hex_dropQ0_dropE0_L2_R1.stim b/visualisations/bb_288_hex_dropQ0_dropE0_L2_R1.stim index d6e9136..2d560ce 100644 --- a/visualisations/bb_288_hex_dropQ0_dropE0_L2_R1.stim +++ b/visualisations/bb_288_hex_dropQ0_dropE0_L2_R1.stim @@ -1176,39 +1176,39 @@ QUBIT_COORDS(11.5, 11) 287 #!pragma POLYGON(0,0,1,0.15) 38 20 284 285 275 193 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 40 22 286 287 277 195 -CX 118 95 277 286 181 190 54 31 71 56 273 282 146 123 50 27 163 148 67 52 2 267 255 240 159 144 25 34 28 5 45 30 88 65 120 97 24 1 137 122 180 157 41 26 84 61 272 249 176 153 59 68 19 4 62 39 214 191 111 96 154 131 15 0 58 35 246 223 150 127 167 152 33 42 242 219 6 271 36 13 259 244 125 134 29 38 128 105 217 226 32 9 121 130 220 197 124 101 141 126 7 16 216 193 233 218 99 108 276 253 3 12 92 69 102 79 184 161 194 171 98 75 155 164 70 47 247 256 207 192 73 82 23 8 66 43 76 53 115 100 158 135 168 145 72 49 129 138 250 227 14 279 44 21 221 230 37 46 10 275 40 17 263 248 89 74 132 109 103 112 224 201 195 204 284 261 11 20 188 165 237 222 280 257 106 83 262 239 77 86 166 143 198 175 265 274 215 200 169 178 258 235 119 104 162 139 251 260 211 196 254 231 264 241 80 57 236 213 51 60 140 117 172 149 229 238 133 142 189 174 232 209 18 283 93 78 136 113 225 234 281 266 185 170 228 205 210 187 114 91 203 212 107 116 206 183 110 87 199 208 202 179 85 94 177 186 81 90 269 278 173 182 63 48 22 287 268 245 285 270 151 160 55 64 243 252 147 156 -TICK -CX 113 154 134 67 17 58 144 77 94 3 205 246 109 150 200 133 197 262 87 128 108 41 179 220 83 124 270 203 56 277 174 107 275 28 266 199 52 273 61 102 82 15 153 194 271 24 57 98 213 254 234 167 117 158 244 177 138 71 30 251 148 81 209 250 75 140 230 163 286 195 249 2 240 173 35 76 26 247 190 99 95 136 127 168 31 72 187 228 208 141 91 132 218 151 112 45 122 55 64 285 49 114 204 137 183 224 260 169 164 73 60 281 69 110 90 23 161 202 182 115 65 106 86 19 274 207 157 198 178 111 279 32 160 93 43 84 135 176 156 89 39 80 171 236 227 268 248 181 131 172 152 85 223 264 253 6 149 214 53 118 191 232 145 210 222 155 126 59 282 215 267 44 12 233 186 119 46 243 123 188 287 40 278 211 27 92 4 225 165 206 283 36 0 221 9 50 256 189 241 18 5 70 20 217 231 272 97 162 261 14 252 185 47 88 1 66 142 51 96 29 139 180 257 10 34 255 116 25 8 229 219 284 130 63 13 54 245 22 201 242 105 146 239 280 193 258 143 184 238 147 104 37 235 276 101 166 175 216 196 129 79 120 100 33 42 263 192 125 38 259 48 269 212 121 78 11 170 103 74 7 16 237 226 159 21 62 68 265 +CX 279 58 160 119 43 110 64 23 135 202 156 115 39 106 60 19 171 262 248 207 131 198 152 111 253 32 191 258 145 236 222 181 126 85 267 70 197 264 227 6 46 269 123 214 287 66 278 237 27 118 4 251 165 232 283 62 0 247 9 76 256 215 241 44 20 243 97 188 261 40 252 211 47 114 1 92 142 77 139 206 257 36 234 169 138 73 34 281 235 14 116 51 231 10 8 255 130 89 13 80 90 25 201 268 105 172 193 284 143 210 238 173 104 63 219 22 175 242 196 155 79 146 100 59 192 151 96 55 38 285 212 147 78 37 239 18 149 216 170 129 53 120 74 33 16 263 226 185 12 259 21 88 282 217 186 121 52 11 113 180 134 93 17 84 144 103 94 29 48 7 205 272 109 176 200 159 87 154 108 67 68 3 179 246 83 150 270 229 174 133 275 54 266 225 61 128 82 41 153 220 271 50 57 124 213 280 117 184 244 203 30 277 148 107 209 276 75 166 230 189 286 221 249 28 240 199 26 273 35 102 56 15 190 125 95 162 127 194 245 24 31 98 187 254 208 167 91 158 218 177 112 71 122 81 183 250 49 140 204 163 260 195 223 2 164 99 69 136 101 168 5 72 161 228 182 141 65 132 86 45 42 265 274 233 157 224 178 137 TICK -CX 32 211 23 132 250 141 143 252 233 54 246 137 219 64 116 271 6 185 192 83 112 267 142 9 224 115 128 19 33 166 89 198 234 101 80 259 239 60 138 5 220 111 193 38 29 162 90 245 85 194 276 167 86 241 21 130 221 66 104 283 263 84 100 279 182 49 168 59 78 257 237 58 73 206 228 119 223 68 93 202 74 253 238 105 160 27 205 26 196 87 197 42 94 249 212 79 117 226 179 0 189 10 170 61 75 208 225 70 35 144 281 102 190 57 108 287 81 214 277 98 186 53 268 159 77 210 63 172 264 155 213 34 204 95 209 30 82 261 55 188 200 91 191 12 92 247 51 184 269 114 187 8 178 69 284 151 24 203 183 4 174 65 275 96 146 37 39 148 285 106 266 157 280 147 201 46 11 120 131 240 243 88 258 125 44 199 134 1 254 121 40 195 145 278 175 20 126 17 272 163 171 16 232 99 227 48 18 173 136 3 218 109 122 13 273 118 14 169 260 127 165 274 255 76 161 270 150 41 251 72 242 133 47 156 28 207 139 248 43 152 229 50 135 244 124 15 230 97 262 129 216 107 235 56 2 181 71 180 153 286 231 52 22 177 67 176 149 282 25 158 236 103 110 265 140 7 222 113 45 154 31 164 36 215 217 62 123 256 +CX 84 75 198 213 273 8 215 238 119 142 59 82 211 234 264 279 214 205 80 95 154 145 58 49 172 187 189 212 93 116 33 56 185 208 125 148 29 52 285 20 217 240 121 144 7 30 99 122 276 267 3 26 92 83 184 175 88 79 155 178 70 61 247 270 63 86 73 96 66 57 268 283 158 149 62 53 129 152 250 241 44 35 221 244 37 60 40 31 132 123 36 27 103 126 18 9 195 218 284 275 11 34 54 69 188 179 14 5 71 94 280 271 146 161 50 65 106 97 163 186 262 253 10 1 67 90 77 100 166 157 255 278 159 182 169 192 258 249 162 153 28 43 251 274 45 68 254 245 120 135 24 39 137 160 236 227 41 64 51 74 140 131 229 252 272 287 133 156 176 191 232 223 136 127 2 17 225 248 19 42 265 0 228 219 22 13 111 134 15 38 114 105 203 226 246 261 107 130 150 165 206 197 110 101 167 190 199 222 242 257 202 193 259 282 85 108 128 143 32 47 177 200 220 235 81 104 124 139 141 164 173 196 216 231 233 256 102 117 6 21 151 174 194 209 55 78 98 113 243 266 147 170 207 230 23 46 269 4 76 91 115 138 168 183 118 109 72 87 210 201 181 204 263 286 89 112 224 239 25 48 281 16 237 260 277 12 180 171 TICK -MX 21 31 35 39 43 47 74 75 78 82 86 90 94 100 104 108 112 116 117 122 123 126 131 134 135 138 139 142 143 145 149 153 160 161 165 170 171 174 175 178 179 182 183 186 187 190 191 192 193 196 197 200 201 204 205 209 212 213 218 219 222 223 227 230 231 234 235 238 239 260 266 275 -MZ 3 7 10 15 19 37 41 50 54 58 59 62 66 70 72 76 84 88 98 99 102 103 106 107 111 114 115 118 119 120 121 125 129 132 133 137 141 147 151 154 155 158 159 162 163 166 167 169 172 173 176 177 180 181 184 185 188 194 195 198 199 202 203 206 207 210 211 214 215 247 259 265 +CX 140 107 253 286 37 70 218 209 122 113 199 232 103 136 0 279 246 237 75 108 150 141 195 228 110 77 242 233 82 49 128 119 173 206 32 23 138 105 183 192 215 224 124 115 169 202 230 197 16 271 226 193 102 93 229 262 194 185 9 42 236 203 265 10 285 6 171 204 86 53 118 85 274 241 213 222 117 126 210 177 145 178 95 104 60 27 81 114 267 12 187 196 91 100 234 201 63 72 273 18 109 142 13 46 283 4 151 184 84 51 161 170 198 189 65 74 208 175 47 56 83 116 94 61 139 148 264 255 214 181 43 52 80 71 58 25 79 112 135 144 172 163 39 48 57 90 68 35 238 205 67 76 149 182 64 31 159 168 127 160 277 22 137 146 212 179 78 69 41 50 123 156 257 266 287 8 88 55 143 152 59 92 180 147 190 157 101 134 235 244 282 249 66 33 186 153 15 24 97 130 1 34 278 245 62 29 263 272 167 176 14 269 260 227 44 11 89 98 154 121 164 131 30 21 259 268 125 158 200 191 275 20 217 250 223 256 7 40 284 251 270 261 17 26 54 45 99 132 174 165 3 36 219 252 280 247 106 73 155 188 2 281 166 133 248 239 211 220 276 243 87 96 162 129 28 19 207 216 254 221 38 5 120 111 240 231 225 258 TICK -RX 21 31 35 39 43 47 74 75 78 82 86 90 94 100 104 108 112 116 117 122 123 126 131 134 135 138 139 142 143 145 149 153 160 161 165 170 171 174 175 178 179 182 183 186 187 190 191 192 193 196 197 200 201 204 205 209 212 213 218 219 222 223 227 230 231 234 235 238 239 260 266 275 -R 3 7 10 15 19 37 41 50 54 58 59 62 66 70 72 76 84 88 98 99 102 103 106 107 111 114 115 118 119 120 121 125 129 132 133 137 141 147 151 154 155 158 159 162 163 166 167 169 172 173 176 177 180 181 184 185 188 194 195 198 199 202 203 206 207 210 211 214 215 247 259 265 +MX 2 3 7 14 15 28 32 37 41 44 54 58 59 62 63 66 67 80 81 84 88 89 99 102 103 106 110 118 120 124 125 128 137 140 150 151 154 155 159 162 166 167 169 172 173 180 194 195 198 199 207 210 211 214 215 217 225 229 236 242 246 254 259 263 264 265 273 276 277 280 284 285 +MZ 4 5 8 12 20 21 26 27 31 34 35 42 46 48 49 52 53 56 61 69 74 90 96 100 104 105 108 112 113 116 126 130 131 134 142 144 148 152 153 156 157 160 165 170 175 178 179 182 191 192 193 196 197 201 204 205 209 222 227 231 239 241 244 245 249 252 256 261 266 271 279 286 TICK -CX 32 211 23 132 250 141 143 252 233 54 246 137 219 64 116 271 6 185 192 83 112 267 142 9 224 115 128 19 33 166 89 198 234 101 80 259 239 60 138 5 220 111 193 38 29 162 90 245 85 194 276 167 86 241 21 130 221 66 104 283 263 84 100 279 182 49 168 59 78 257 237 58 73 206 228 119 223 68 93 202 74 253 238 105 160 27 205 26 196 87 197 42 94 249 212 79 117 226 179 0 189 10 170 61 75 208 225 70 35 144 281 102 190 57 108 287 81 214 277 98 186 53 268 159 77 210 63 172 264 155 213 34 204 95 209 30 82 261 55 188 200 91 191 12 92 247 51 184 269 114 187 8 178 69 284 151 24 203 183 4 174 65 275 96 146 37 39 148 285 106 266 157 280 147 201 46 11 120 131 240 243 88 258 125 44 199 134 1 254 121 40 195 145 278 175 20 126 17 272 163 171 16 232 99 227 48 18 173 136 3 218 109 122 13 273 118 14 169 260 127 165 274 255 76 161 270 150 41 251 72 242 133 47 156 28 207 139 248 43 152 229 50 135 244 124 15 230 97 262 129 216 107 235 56 2 181 71 180 153 286 231 52 22 177 67 176 149 282 25 158 236 103 110 265 140 7 222 113 45 154 31 164 36 215 217 62 123 256 +RX 2 3 7 14 15 28 32 37 41 44 54 58 59 62 63 66 67 80 81 84 88 89 99 102 103 106 110 118 120 124 125 128 137 140 150 151 154 155 159 162 166 167 169 172 173 180 194 195 198 199 207 210 211 214 215 217 225 229 236 242 246 254 259 263 264 265 273 276 277 280 284 285 +R 4 5 8 12 20 21 26 27 31 34 35 42 46 48 49 52 53 56 61 69 74 90 96 100 104 105 108 112 113 116 126 130 131 134 142 144 148 152 153 156 157 160 165 170 175 178 179 182 191 192 193 196 197 201 204 205 209 222 227 231 239 241 244 245 249 252 256 261 266 271 279 286 TICK -CX 113 154 134 67 17 58 144 77 94 3 205 246 109 150 200 133 197 262 87 128 108 41 179 220 83 124 270 203 56 277 174 107 275 28 266 199 52 273 61 102 82 15 153 194 271 24 57 98 213 254 234 167 117 158 244 177 138 71 30 251 148 81 209 250 75 140 230 163 286 195 249 2 240 173 35 76 26 247 190 99 95 136 127 168 31 72 187 228 208 141 91 132 218 151 112 45 122 55 64 285 49 114 204 137 183 224 260 169 164 73 60 281 69 110 90 23 161 202 182 115 65 106 86 19 274 207 157 198 178 111 279 32 160 93 43 84 135 176 156 89 39 80 171 236 227 268 248 181 131 172 152 85 223 264 253 6 149 214 53 118 191 232 145 210 222 155 126 59 282 215 267 44 12 233 186 119 46 243 123 188 287 40 278 211 27 92 4 225 165 206 283 36 0 221 9 50 256 189 241 18 5 70 20 217 231 272 97 162 261 14 252 185 47 88 1 66 142 51 96 29 139 180 257 10 34 255 116 25 8 229 219 284 130 63 13 54 245 22 201 242 105 146 239 280 193 258 143 184 238 147 104 37 235 276 101 166 175 216 196 129 79 120 100 33 42 263 192 125 38 259 48 269 212 121 78 11 170 103 74 7 16 237 226 159 21 62 68 265 +CX 140 107 253 286 37 70 218 209 122 113 199 232 103 136 0 279 246 237 75 108 150 141 195 228 110 77 242 233 82 49 128 119 173 206 32 23 138 105 183 192 215 224 124 115 169 202 230 197 16 271 226 193 102 93 229 262 194 185 9 42 236 203 265 10 285 6 171 204 86 53 118 85 274 241 213 222 117 126 210 177 145 178 95 104 60 27 81 114 267 12 187 196 91 100 234 201 63 72 273 18 109 142 13 46 283 4 151 184 84 51 161 170 198 189 65 74 208 175 47 56 83 116 94 61 139 148 264 255 214 181 43 52 80 71 58 25 79 112 135 144 172 163 39 48 57 90 68 35 238 205 67 76 149 182 64 31 159 168 127 160 277 22 137 146 212 179 78 69 41 50 123 156 257 266 287 8 88 55 143 152 59 92 180 147 190 157 101 134 235 244 282 249 66 33 186 153 15 24 97 130 1 34 278 245 62 29 263 272 167 176 14 269 260 227 44 11 89 98 154 121 164 131 30 21 259 268 125 158 200 191 275 20 217 250 223 256 7 40 284 251 270 261 17 26 54 45 99 132 174 165 3 36 219 252 280 247 106 73 155 188 2 281 166 133 248 239 211 220 276 243 87 96 162 129 28 19 207 216 254 221 38 5 120 111 240 231 225 258 TICK -CX 118 95 277 286 181 190 54 31 71 56 273 282 146 123 50 27 163 148 67 52 2 267 255 240 159 144 25 34 28 5 45 30 88 65 120 97 24 1 137 122 180 157 41 26 84 61 272 249 176 153 59 68 19 4 62 39 214 191 111 96 154 131 15 0 58 35 246 223 150 127 167 152 33 42 242 219 6 271 36 13 259 244 125 134 29 38 128 105 217 226 32 9 121 130 220 197 124 101 141 126 7 16 216 193 233 218 99 108 276 253 3 12 92 69 102 79 184 161 194 171 98 75 155 164 70 47 247 256 207 192 73 82 23 8 66 43 76 53 115 100 158 135 168 145 72 49 129 138 250 227 14 279 44 21 221 230 37 46 10 275 40 17 263 248 89 74 132 109 103 112 224 201 195 204 284 261 11 20 188 165 237 222 280 257 106 83 262 239 77 86 166 143 198 175 265 274 215 200 169 178 258 235 119 104 162 139 251 260 211 196 254 231 264 241 80 57 236 213 51 60 140 117 172 149 229 238 133 142 189 174 232 209 18 283 93 78 136 113 225 234 281 266 185 170 228 205 210 187 114 91 203 212 107 116 206 183 110 87 199 208 202 179 85 94 177 186 81 90 269 278 173 182 63 48 22 287 268 245 285 270 151 160 55 64 243 252 147 156 +CX 84 75 198 213 273 8 215 238 119 142 59 82 211 234 264 279 214 205 80 95 154 145 58 49 172 187 189 212 93 116 33 56 185 208 125 148 29 52 285 20 217 240 121 144 7 30 99 122 276 267 3 26 92 83 184 175 88 79 155 178 70 61 247 270 63 86 73 96 66 57 268 283 158 149 62 53 129 152 250 241 44 35 221 244 37 60 40 31 132 123 36 27 103 126 18 9 195 218 284 275 11 34 54 69 188 179 14 5 71 94 280 271 146 161 50 65 106 97 163 186 262 253 10 1 67 90 77 100 166 157 255 278 159 182 169 192 258 249 162 153 28 43 251 274 45 68 254 245 120 135 24 39 137 160 236 227 41 64 51 74 140 131 229 252 272 287 133 156 176 191 232 223 136 127 2 17 225 248 19 42 265 0 228 219 22 13 111 134 15 38 114 105 203 226 246 261 107 130 150 165 206 197 110 101 167 190 199 222 242 257 202 193 259 282 85 108 128 143 32 47 177 200 220 235 81 104 124 139 141 164 173 196 216 231 233 256 102 117 6 21 151 174 194 209 55 78 98 113 243 266 147 170 207 230 23 46 269 4 76 91 115 138 168 183 118 109 72 87 210 201 181 204 263 286 89 112 224 239 25 48 281 16 237 260 277 12 180 171 TICK CX 279 58 160 119 43 110 64 23 135 202 156 115 39 106 60 19 171 262 248 207 131 198 152 111 253 32 191 258 145 236 222 181 126 85 267 70 197 264 227 6 46 269 123 214 287 66 278 237 27 118 4 251 165 232 283 62 0 247 9 76 256 215 241 44 20 243 97 188 261 40 252 211 47 114 1 92 142 77 139 206 257 36 234 169 138 73 34 281 235 14 116 51 231 10 8 255 130 89 13 80 90 25 201 268 105 172 193 284 143 210 238 173 104 63 219 22 175 242 196 155 79 146 100 59 192 151 96 55 38 285 212 147 78 37 239 18 149 216 170 129 53 120 74 33 16 263 226 185 12 259 21 88 282 217 186 121 52 11 113 180 134 93 17 84 144 103 94 29 48 7 205 272 109 176 200 159 87 154 108 67 68 3 179 246 83 150 270 229 174 133 275 54 266 225 61 128 82 41 153 220 271 50 57 124 213 280 117 184 244 203 30 277 148 107 209 276 75 166 230 189 286 221 249 28 240 199 26 273 35 102 56 15 190 125 95 162 127 194 245 24 31 98 187 254 208 167 91 158 218 177 112 71 122 81 183 250 49 140 204 163 260 195 223 2 164 99 69 136 101 168 5 72 161 228 182 141 65 132 86 45 42 265 274 233 157 224 178 137 TICK -CX 84 75 198 213 273 8 215 238 119 142 59 82 211 234 264 279 214 205 80 95 154 145 58 49 172 187 189 212 93 116 33 56 185 208 125 148 29 52 285 20 217 240 121 144 7 30 99 122 276 267 3 26 92 83 184 175 88 79 155 178 70 61 247 270 63 86 73 96 66 57 268 283 158 149 62 53 129 152 250 241 44 35 221 244 37 60 40 31 132 123 36 27 103 126 18 9 195 218 284 275 11 34 54 69 188 179 14 5 71 94 280 271 146 161 50 65 106 97 163 186 262 253 10 1 67 90 77 100 166 157 255 278 159 182 169 192 258 249 162 153 28 43 251 274 45 68 254 245 120 135 24 39 137 160 236 227 41 64 51 74 140 131 229 252 272 287 133 156 176 191 232 223 136 127 2 17 225 248 19 42 265 0 228 219 22 13 111 134 15 38 114 105 203 226 246 261 107 130 150 165 206 197 110 101 167 190 199 222 242 257 202 193 259 282 85 108 128 143 32 47 177 200 220 235 81 104 124 139 141 164 173 196 216 231 233 256 102 117 6 21 151 174 194 209 55 78 98 113 243 266 147 170 207 230 23 46 269 4 76 91 115 138 168 183 118 109 72 87 210 201 181 204 263 286 89 112 224 239 25 48 281 16 237 260 277 12 180 171 +CX 118 95 277 286 181 190 54 31 71 56 273 282 146 123 50 27 163 148 67 52 2 267 255 240 159 144 25 34 28 5 45 30 88 65 120 97 24 1 137 122 180 157 41 26 84 61 272 249 176 153 59 68 19 4 62 39 214 191 111 96 154 131 15 0 58 35 246 223 150 127 167 152 33 42 242 219 6 271 36 13 259 244 125 134 29 38 128 105 217 226 32 9 121 130 220 197 124 101 141 126 7 16 216 193 233 218 99 108 276 253 3 12 92 69 102 79 184 161 194 171 98 75 155 164 70 47 247 256 207 192 73 82 23 8 66 43 76 53 115 100 158 135 168 145 72 49 129 138 250 227 14 279 44 21 221 230 37 46 10 275 40 17 263 248 89 74 132 109 103 112 224 201 195 204 284 261 11 20 188 165 237 222 280 257 106 83 262 239 77 86 166 143 198 175 265 274 215 200 169 178 258 235 119 104 162 139 251 260 211 196 254 231 264 241 80 57 236 213 51 60 140 117 172 149 229 238 133 142 189 174 232 209 18 283 93 78 136 113 225 234 281 266 185 170 228 205 210 187 114 91 203 212 107 116 206 183 110 87 199 208 202 179 85 94 177 186 81 90 269 278 173 182 63 48 22 287 268 245 285 270 151 160 55 64 243 252 147 156 TICK -CX 130 97 129 162 222 213 34 1 185 194 126 117 221 254 37 70 218 209 122 113 108 75 199 232 103 136 0 279 195 228 281 2 82 49 46 13 173 206 77 110 138 105 215 224 169 202 119 128 230 197 16 271 226 193 147 180 51 84 229 262 112 79 133 166 269 14 189 198 93 102 204 171 285 6 203 236 86 53 107 140 274 241 4 283 178 145 85 118 100 91 20 275 177 210 60 27 81 114 192 183 142 109 96 87 234 201 63 72 273 18 74 65 151 184 55 88 116 83 243 276 208 175 8 287 94 61 48 39 43 52 80 71 90 57 182 149 181 214 68 35 163 172 238 205 104 95 67 76 160 127 64 31 255 264 196 187 25 58 159 168 277 22 137 146 212 179 78 69 41 50 123 156 170 161 59 92 286 253 115 124 190 157 56 47 19 28 282 249 111 120 186 153 15 24 278 245 144 135 263 272 167 176 33 66 260 227 44 11 89 98 154 121 164 131 30 21 259 268 125 158 200 191 10 265 29 62 256 223 217 250 252 219 237 246 141 150 7 40 270 261 17 26 54 45 99 132 174 165 3 36 233 242 266 257 251 284 155 188 248 239 211 220 152 143 247 280 12 267 42 9 244 235 73 106 207 216 23 32 148 139 134 101 38 5 240 231 225 258 +CX 113 154 134 67 17 58 144 77 94 3 205 246 109 150 200 133 197 262 87 128 108 41 179 220 83 124 270 203 56 277 174 107 275 28 266 199 52 273 61 102 82 15 153 194 271 24 57 98 213 254 234 167 117 158 244 177 138 71 30 251 148 81 209 250 75 140 230 163 286 195 249 2 240 173 35 76 26 247 190 99 95 136 127 168 31 72 187 228 208 141 91 132 218 151 112 45 122 55 64 285 49 114 204 137 183 224 260 169 164 73 60 281 69 110 90 23 161 202 182 115 65 106 86 19 274 207 157 198 178 111 279 32 160 93 43 84 135 176 156 89 39 80 171 236 227 268 248 181 131 172 152 85 223 264 253 6 149 214 53 118 191 232 145 210 222 155 126 59 282 215 267 44 12 233 186 119 46 243 123 188 287 40 278 211 27 92 4 225 165 206 283 36 0 221 9 50 256 189 241 18 5 70 20 217 231 272 97 162 261 14 252 185 47 88 1 66 142 51 96 29 139 180 257 10 34 255 116 25 8 229 219 284 130 63 13 54 245 22 201 242 105 146 239 280 193 258 143 184 238 147 104 37 235 276 101 166 175 216 196 129 79 120 100 33 42 263 192 125 38 259 48 269 212 121 78 11 170 103 74 7 16 237 226 159 21 62 68 265 TICK -MX 3 7 10 15 19 23 25 29 33 37 41 44 51 54 55 59 63 67 73 77 80 81 85 89 93 99 103 107 111 115 119 125 129 133 137 141 147 151 154 155 159 163 167 169 173 177 181 185 189 195 199 203 207 211 215 217 221 225 229 233 237 243 247 251 255 259 263 269 273 277 281 285 -MZ 1 5 9 13 21 26 27 31 35 39 47 49 52 53 57 61 65 69 75 79 83 87 91 95 97 101 105 109 113 117 127 131 135 139 143 145 149 153 156 157 161 165 171 175 179 183 187 191 193 197 201 205 209 213 219 223 227 231 235 239 241 245 249 253 257 261 267 271 275 279 283 287 +CX 32 211 23 132 250 141 143 252 154 45 115 224 19 128 219 64 5 138 46 201 116 271 111 220 102 281 20 175 98 277 167 276 234 101 207 28 193 38 125 258 29 162 90 245 76 255 121 254 198 89 221 66 12 191 194 85 104 283 263 84 17 126 8 187 249 94 109 218 214 81 119 228 100 279 130 21 172 63 195 40 168 59 88 243 83 192 9 142 129 262 205 26 215 36 196 87 61 170 52 231 202 93 62 217 117 226 179 0 189 10 75 208 185 6 108 287 68 223 91 200 77 210 158 25 278 145 144 35 49 182 264 155 213 34 204 95 199 44 82 261 105 238 92 247 65 174 51 184 157 266 269 114 70 225 188 55 270 161 183 4 56 235 79 212 275 96 146 37 39 148 285 106 280 147 131 240 253 74 244 135 30 209 53 186 134 1 120 11 159 268 267 112 171 16 232 99 227 48 18 173 136 3 122 13 27 160 54 233 14 169 260 127 69 178 151 284 60 239 241 86 150 41 206 73 251 72 42 197 242 133 47 156 274 165 107 216 139 248 257 78 43 152 229 50 124 15 230 97 2 181 166 33 153 286 57 190 118 273 163 272 22 177 67 176 149 282 203 24 58 237 180 71 236 103 110 265 259 80 140 7 222 113 31 164 137 246 123 256 TICK -RX 3 7 10 15 19 23 25 29 33 37 41 44 51 54 55 59 63 67 73 77 80 81 85 89 93 99 103 107 111 115 119 125 129 133 137 141 147 151 154 155 159 163 167 169 173 177 181 185 189 195 199 203 207 211 215 217 221 225 229 233 237 243 247 251 255 259 263 269 273 277 281 285 -R 1 5 9 13 21 26 27 31 35 39 47 49 52 53 57 61 65 69 75 79 83 87 91 95 97 101 105 109 113 117 127 131 135 139 143 145 149 153 156 157 161 165 171 175 179 183 187 191 193 197 201 205 209 213 219 223 227 231 235 239 241 245 249 253 257 261 267 271 275 279 283 287 +MX 5 8 9 12 17 20 27 30 31 39 42 43 46 47 49 52 53 56 57 60 61 65 68 69 75 79 82 83 90 91 100 104 105 108 109 116 117 122 123 130 131 134 139 143 144 149 153 157 171 179 183 193 196 204 205 213 219 222 227 230 234 241 244 249 253 257 260 267 270 274 275 278 +MZ 3 6 7 10 11 15 24 25 28 33 36 37 40 41 44 45 50 55 59 63 66 71 72 73 80 81 84 85 89 93 99 103 106 114 128 132 133 141 147 155 162 169 173 176 177 181 184 210 211 216 217 220 224 225 228 233 237 243 246 247 254 255 258 262 265 268 272 273 276 277 281 284 TICK -CX 130 97 129 162 222 213 34 1 185 194 126 117 221 254 37 70 218 209 122 113 108 75 199 232 103 136 0 279 195 228 281 2 82 49 46 13 173 206 77 110 138 105 215 224 169 202 119 128 230 197 16 271 226 193 147 180 51 84 229 262 112 79 133 166 269 14 189 198 93 102 204 171 285 6 203 236 86 53 107 140 274 241 4 283 178 145 85 118 100 91 20 275 177 210 60 27 81 114 192 183 142 109 96 87 234 201 63 72 273 18 74 65 151 184 55 88 116 83 243 276 208 175 8 287 94 61 48 39 43 52 80 71 90 57 182 149 181 214 68 35 163 172 238 205 104 95 67 76 160 127 64 31 255 264 196 187 25 58 159 168 277 22 137 146 212 179 78 69 41 50 123 156 170 161 59 92 286 253 115 124 190 157 56 47 19 28 282 249 111 120 186 153 15 24 278 245 144 135 263 272 167 176 33 66 260 227 44 11 89 98 154 121 164 131 30 21 259 268 125 158 200 191 10 265 29 62 256 223 217 250 252 219 237 246 141 150 7 40 270 261 17 26 54 45 99 132 174 165 3 36 233 242 266 257 251 284 155 188 248 239 211 220 152 143 247 280 12 267 42 9 244 235 73 106 207 216 23 32 148 139 134 101 38 5 240 231 225 258 +RX 5 8 9 12 17 20 27 30 31 39 42 43 46 47 49 52 53 56 57 60 61 65 68 69 75 79 82 83 90 91 100 104 105 108 109 116 117 122 123 130 131 134 139 143 144 149 153 157 171 179 183 193 196 204 205 213 219 222 227 230 234 241 244 249 253 257 260 267 270 274 275 278 +R 3 6 7 10 11 15 24 25 28 33 36 37 40 41 44 45 50 55 59 63 66 71 72 73 80 81 84 85 89 93 99 103 106 114 128 132 133 141 147 155 162 169 173 176 177 181 184 210 211 216 217 220 224 225 228 233 237 243 246 247 254 255 258 262 265 268 272 273 276 277 281 284 TICK -CX 84 75 198 213 273 8 215 238 119 142 59 82 211 234 264 279 214 205 80 95 154 145 58 49 172 187 189 212 93 116 33 56 185 208 125 148 29 52 285 20 217 240 121 144 7 30 99 122 276 267 3 26 92 83 184 175 88 79 155 178 70 61 247 270 63 86 73 96 66 57 268 283 158 149 62 53 129 152 250 241 44 35 221 244 37 60 40 31 132 123 36 27 103 126 18 9 195 218 284 275 11 34 54 69 188 179 14 5 71 94 280 271 146 161 50 65 106 97 163 186 262 253 10 1 67 90 77 100 166 157 255 278 159 182 169 192 258 249 162 153 28 43 251 274 45 68 254 245 120 135 24 39 137 160 236 227 41 64 51 74 140 131 229 252 272 287 133 156 176 191 232 223 136 127 2 17 225 248 19 42 265 0 228 219 22 13 111 134 15 38 114 105 203 226 246 261 107 130 150 165 206 197 110 101 167 190 199 222 242 257 202 193 259 282 85 108 128 143 32 47 177 200 220 235 81 104 124 139 141 164 173 196 216 231 233 256 102 117 6 21 151 174 194 209 55 78 98 113 243 266 147 170 207 230 23 46 269 4 76 91 115 138 168 183 118 109 72 87 210 201 181 204 263 286 89 112 224 239 25 48 281 16 237 260 277 12 180 171 +CX 32 211 23 132 250 141 143 252 154 45 115 224 19 128 219 64 5 138 46 201 116 271 111 220 102 281 20 175 98 277 167 276 234 101 207 28 193 38 125 258 29 162 90 245 76 255 121 254 198 89 221 66 12 191 194 85 104 283 263 84 17 126 8 187 249 94 109 218 214 81 119 228 100 279 130 21 172 63 195 40 168 59 88 243 83 192 9 142 129 262 205 26 215 36 196 87 61 170 52 231 202 93 62 217 117 226 179 0 189 10 75 208 185 6 108 287 68 223 91 200 77 210 158 25 278 145 144 35 49 182 264 155 213 34 204 95 199 44 82 261 105 238 92 247 65 174 51 184 157 266 269 114 70 225 188 55 270 161 183 4 56 235 79 212 275 96 146 37 39 148 285 106 280 147 131 240 253 74 244 135 30 209 53 186 134 1 120 11 159 268 267 112 171 16 232 99 227 48 18 173 136 3 122 13 27 160 54 233 14 169 260 127 69 178 151 284 60 239 241 86 150 41 206 73 251 72 42 197 242 133 47 156 274 165 107 216 139 248 257 78 43 152 229 50 124 15 230 97 2 181 166 33 153 286 57 190 118 273 163 272 22 177 67 176 149 282 203 24 58 237 180 71 236 103 110 265 259 80 140 7 222 113 31 164 137 246 123 256 TICK -CX 279 58 160 119 43 110 64 23 135 202 156 115 39 106 60 19 171 262 248 207 131 198 152 111 253 32 191 258 145 236 222 181 126 85 267 70 197 264 227 6 46 269 123 214 287 66 278 237 27 118 4 251 165 232 283 62 0 247 9 76 256 215 241 44 20 243 97 188 261 40 252 211 47 114 1 92 142 77 139 206 257 36 234 169 138 73 34 281 235 14 116 51 231 10 8 255 130 89 13 80 90 25 201 268 105 172 193 284 143 210 238 173 104 63 219 22 175 242 196 155 79 146 100 59 192 151 96 55 38 285 212 147 78 37 239 18 149 216 170 129 53 120 74 33 16 263 226 185 12 259 21 88 282 217 186 121 52 11 113 180 134 93 17 84 144 103 94 29 48 7 205 272 109 176 200 159 87 154 108 67 68 3 179 246 83 150 270 229 174 133 275 54 266 225 61 128 82 41 153 220 271 50 57 124 213 280 117 184 244 203 30 277 148 107 209 276 75 166 230 189 286 221 249 28 240 199 26 273 35 102 56 15 190 125 95 162 127 194 245 24 31 98 187 254 208 167 91 158 218 177 112 71 122 81 183 250 49 140 204 163 260 195 223 2 164 99 69 136 101 168 5 72 161 228 182 141 65 132 86 45 42 265 274 233 157 224 178 137 +CX 113 154 134 67 17 58 144 77 94 3 205 246 109 150 200 133 197 262 87 128 108 41 179 220 83 124 270 203 56 277 174 107 275 28 266 199 52 273 61 102 82 15 153 194 271 24 57 98 213 254 234 167 117 158 244 177 138 71 30 251 148 81 209 250 75 140 230 163 286 195 249 2 240 173 35 76 26 247 190 99 95 136 127 168 31 72 187 228 208 141 91 132 218 151 112 45 122 55 64 285 49 114 204 137 183 224 260 169 164 73 60 281 69 110 90 23 161 202 182 115 65 106 86 19 274 207 157 198 178 111 279 32 160 93 43 84 135 176 156 89 39 80 171 236 227 268 248 181 131 172 152 85 223 264 253 6 149 214 53 118 191 232 145 210 222 155 126 59 282 215 267 44 12 233 186 119 46 243 123 188 287 40 278 211 27 92 4 225 165 206 283 36 0 221 9 50 256 189 241 18 5 70 20 217 231 272 97 162 261 14 252 185 47 88 1 66 142 51 96 29 139 180 257 10 34 255 116 25 8 229 219 284 130 63 13 54 245 22 201 242 105 146 239 280 193 258 143 184 238 147 104 37 235 276 101 166 175 216 196 129 79 120 100 33 42 263 192 125 38 259 48 269 212 121 78 11 170 103 74 7 16 237 226 159 21 62 68 265 +TICK +CX 118 95 277 286 181 190 54 31 71 56 273 282 146 123 50 27 163 148 67 52 2 267 255 240 159 144 25 34 28 5 45 30 88 65 120 97 24 1 137 122 180 157 41 26 84 61 272 249 176 153 59 68 19 4 62 39 214 191 111 96 154 131 15 0 58 35 246 223 150 127 167 152 33 42 242 219 6 271 36 13 259 244 125 134 29 38 128 105 217 226 32 9 121 130 220 197 124 101 141 126 7 16 216 193 233 218 99 108 276 253 3 12 92 69 102 79 184 161 194 171 98 75 155 164 70 47 247 256 207 192 73 82 23 8 66 43 76 53 115 100 158 135 168 145 72 49 129 138 250 227 14 279 44 21 221 230 37 46 10 275 40 17 263 248 89 74 132 109 103 112 224 201 195 204 284 261 11 20 188 165 237 222 280 257 106 83 262 239 77 86 166 143 198 175 265 274 215 200 169 178 258 235 119 104 162 139 251 260 211 196 254 231 264 241 80 57 236 213 51 60 140 117 172 149 229 238 133 142 189 174 232 209 18 283 93 78 136 113 225 234 281 266 185 170 228 205 210 187 114 91 203 212 107 116 206 183 110 87 199 208 202 179 85 94 177 186 81 90 269 278 173 182 63 48 22 287 268 245 285 270 151 160 55 64 243 252 147 156 TICK diff --git a/visualisations/bb_288_hex_dropQ1_dropE0_L3_R1.stim b/visualisations/bb_288_hex_dropQ1_dropE0_L3_R1.stim new file mode 100644 index 0000000..a963d9c --- /dev/null +++ b/visualisations/bb_288_hex_dropQ1_dropE0_L3_R1.stim @@ -0,0 +1,1252 @@ +##! GATESTYLE DROOP=0 THICKNESS=1.5 +# Legend +# Qubits: L (c=0) = gold, R (c=1) = mediumseagreen +# Connections by class (name: colour): +# - A2: #4361ee +# - A2B2^-1: #2a9d8f +# - A3: #e76f51 +# - A3B3^-1: #f4a261 +# - B2: #e9c46a +# - B3: #8a5cff +##! EMBEDDING TYPE=TORUS LX=12 LY=12 +##! SHEET NAME=QUBITS Z=0 +##! SHEET NAME=A2 Z=1 +##! SHEET NAME=A2B2^-1 Z=2 +##! SHEET NAME=A3 Z=3 +##! SHEET NAME=A3B3^-1 Z=4 +##! SHEET NAME=B2 Z=5 +##! SHEET NAME=B3 Z=6 +##! SHEET NAME=UNTX Z=7 +##! SHEET NAME=UNTZ Z=8 +##! SHEET NAME=ANTIX Z=9 +##! SHEET NAME=ANTIZ Z=10 +##! SHEET NAME=PRODX Z=11 +##! SHEET NAME=PRODZ Z=12 +##! SHEET NAME=GAUGEX Z=13 +##! SHEET NAME=GAUGEZ Z=14 +##! QUBIT Q=0 SHEET=QUBITS X=0 Y=0.5 COLOUR=gold +QUBIT_COORDS(0, 0.5) 0 +##! QUBIT Q=1 SHEET=QUBITS X=0.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 0) 1 +##! QUBIT Q=2 SHEET=QUBITS X=0 Y=1.5 COLOUR=gold +QUBIT_COORDS(0, 1.5) 2 +##! QUBIT Q=3 SHEET=QUBITS X=0.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 1) 3 +##! QUBIT Q=4 SHEET=QUBITS X=0 Y=2.5 COLOUR=gold +QUBIT_COORDS(0, 2.5) 4 +##! QUBIT Q=5 SHEET=QUBITS X=0.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 2) 5 +##! QUBIT Q=6 SHEET=QUBITS X=0 Y=3.5 COLOUR=gold +QUBIT_COORDS(0, 3.5) 6 +##! QUBIT Q=7 SHEET=QUBITS X=0.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 3) 7 +##! QUBIT Q=8 SHEET=QUBITS X=0 Y=4.5 COLOUR=gold +QUBIT_COORDS(0, 4.5) 8 +##! QUBIT Q=9 SHEET=QUBITS X=0.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 4) 9 +##! QUBIT Q=10 SHEET=QUBITS X=0 Y=5.5 COLOUR=gold +QUBIT_COORDS(0, 5.5) 10 +##! QUBIT Q=11 SHEET=QUBITS X=0.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 5) 11 +##! QUBIT Q=12 SHEET=QUBITS X=0 Y=6.5 COLOUR=gold +QUBIT_COORDS(0, 6.5) 12 +##! QUBIT Q=13 SHEET=QUBITS X=0.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 6) 13 +##! QUBIT Q=14 SHEET=QUBITS X=0 Y=7.5 COLOUR=gold +QUBIT_COORDS(0, 7.5) 14 +##! QUBIT Q=15 SHEET=QUBITS X=0.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 7) 15 +##! QUBIT Q=16 SHEET=QUBITS X=0 Y=8.5 COLOUR=gold +QUBIT_COORDS(0, 8.5) 16 +##! QUBIT Q=17 SHEET=QUBITS X=0.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 8) 17 +##! QUBIT Q=18 SHEET=QUBITS X=0 Y=9.5 COLOUR=gold +QUBIT_COORDS(0, 9.5) 18 +##! QUBIT Q=19 SHEET=QUBITS X=0.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 9) 19 +##! QUBIT Q=20 SHEET=QUBITS X=0 Y=10.5 COLOUR=gold +QUBIT_COORDS(0, 10.5) 20 +##! QUBIT Q=21 SHEET=QUBITS X=0.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 10) 21 +##! QUBIT Q=22 SHEET=QUBITS X=0 Y=11.5 COLOUR=gold +QUBIT_COORDS(0, 11.5) 22 +##! QUBIT Q=23 SHEET=QUBITS X=0.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(0.5, 11) 23 +##! QUBIT Q=24 SHEET=QUBITS X=1 Y=0.5 COLOUR=gold +QUBIT_COORDS(1, 0.5) 24 +##! QUBIT Q=25 SHEET=QUBITS X=1.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 0) 25 +##! QUBIT Q=26 SHEET=QUBITS X=1 Y=1.5 COLOUR=gold +QUBIT_COORDS(1, 1.5) 26 +##! QUBIT Q=27 SHEET=QUBITS X=1.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 1) 27 +##! QUBIT Q=28 SHEET=QUBITS X=1 Y=2.5 COLOUR=gold +QUBIT_COORDS(1, 2.5) 28 +##! QUBIT Q=29 SHEET=QUBITS X=1.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 2) 29 +##! QUBIT Q=30 SHEET=QUBITS X=1 Y=3.5 COLOUR=gold +QUBIT_COORDS(1, 3.5) 30 +##! QUBIT Q=31 SHEET=QUBITS X=1.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 3) 31 +##! QUBIT Q=32 SHEET=QUBITS X=1 Y=4.5 COLOUR=gold +QUBIT_COORDS(1, 4.5) 32 +##! QUBIT Q=33 SHEET=QUBITS X=1.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 4) 33 +##! QUBIT Q=34 SHEET=QUBITS X=1 Y=5.5 COLOUR=gold +QUBIT_COORDS(1, 5.5) 34 +##! QUBIT Q=35 SHEET=QUBITS X=1.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 5) 35 +##! QUBIT Q=36 SHEET=QUBITS X=1 Y=6.5 COLOUR=gold +QUBIT_COORDS(1, 6.5) 36 +##! QUBIT Q=37 SHEET=QUBITS X=1.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 6) 37 +##! QUBIT Q=38 SHEET=QUBITS X=1 Y=7.5 COLOUR=gold +QUBIT_COORDS(1, 7.5) 38 +##! QUBIT Q=39 SHEET=QUBITS X=1.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 7) 39 +##! QUBIT Q=40 SHEET=QUBITS X=1 Y=8.5 COLOUR=gold +QUBIT_COORDS(1, 8.5) 40 +##! QUBIT Q=41 SHEET=QUBITS X=1.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 8) 41 +##! QUBIT Q=42 SHEET=QUBITS X=1 Y=9.5 COLOUR=gold +QUBIT_COORDS(1, 9.5) 42 +##! QUBIT Q=43 SHEET=QUBITS X=1.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 9) 43 +##! QUBIT Q=44 SHEET=QUBITS X=1 Y=10.5 COLOUR=gold +QUBIT_COORDS(1, 10.5) 44 +##! QUBIT Q=45 SHEET=QUBITS X=1.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 10) 45 +##! QUBIT Q=46 SHEET=QUBITS X=1 Y=11.5 COLOUR=gold +QUBIT_COORDS(1, 11.5) 46 +##! QUBIT Q=47 SHEET=QUBITS X=1.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(1.5, 11) 47 +##! QUBIT Q=48 SHEET=QUBITS X=2 Y=0.5 COLOUR=gold +QUBIT_COORDS(2, 0.5) 48 +##! QUBIT Q=49 SHEET=QUBITS X=2.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 0) 49 +##! QUBIT Q=50 SHEET=QUBITS X=2 Y=1.5 COLOUR=gold +QUBIT_COORDS(2, 1.5) 50 +##! QUBIT Q=51 SHEET=QUBITS X=2.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 1) 51 +##! QUBIT Q=52 SHEET=QUBITS X=2 Y=2.5 COLOUR=gold +QUBIT_COORDS(2, 2.5) 52 +##! QUBIT Q=53 SHEET=QUBITS X=2.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 2) 53 +##! QUBIT Q=54 SHEET=QUBITS X=2 Y=3.5 COLOUR=gold +QUBIT_COORDS(2, 3.5) 54 +##! QUBIT Q=55 SHEET=QUBITS X=2.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 3) 55 +##! QUBIT Q=56 SHEET=QUBITS X=2 Y=4.5 COLOUR=gold +QUBIT_COORDS(2, 4.5) 56 +##! QUBIT Q=57 SHEET=QUBITS X=2.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 4) 57 +##! QUBIT Q=58 SHEET=QUBITS X=2 Y=5.5 COLOUR=gold +QUBIT_COORDS(2, 5.5) 58 +##! QUBIT Q=59 SHEET=QUBITS X=2.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 5) 59 +##! QUBIT Q=60 SHEET=QUBITS X=2 Y=6.5 COLOUR=gold +QUBIT_COORDS(2, 6.5) 60 +##! QUBIT Q=61 SHEET=QUBITS X=2.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 6) 61 +##! QUBIT Q=62 SHEET=QUBITS X=2 Y=7.5 COLOUR=gold +QUBIT_COORDS(2, 7.5) 62 +##! QUBIT Q=63 SHEET=QUBITS X=2.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 7) 63 +##! QUBIT Q=64 SHEET=QUBITS X=2 Y=8.5 COLOUR=gold +QUBIT_COORDS(2, 8.5) 64 +##! QUBIT Q=65 SHEET=QUBITS X=2.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 8) 65 +##! QUBIT Q=66 SHEET=QUBITS X=2 Y=9.5 COLOUR=gold +QUBIT_COORDS(2, 9.5) 66 +##! QUBIT Q=67 SHEET=QUBITS X=2.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 9) 67 +##! QUBIT Q=68 SHEET=QUBITS X=2 Y=10.5 COLOUR=gold +QUBIT_COORDS(2, 10.5) 68 +##! QUBIT Q=69 SHEET=QUBITS X=2.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 10) 69 +##! QUBIT Q=70 SHEET=QUBITS X=2 Y=11.5 COLOUR=gold +QUBIT_COORDS(2, 11.5) 70 +##! QUBIT Q=71 SHEET=QUBITS X=2.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(2.5, 11) 71 +##! QUBIT Q=72 SHEET=QUBITS X=3 Y=0.5 COLOUR=gold +QUBIT_COORDS(3, 0.5) 72 +##! QUBIT Q=73 SHEET=QUBITS X=3.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 0) 73 +##! QUBIT Q=74 SHEET=QUBITS X=3 Y=1.5 COLOUR=gold +QUBIT_COORDS(3, 1.5) 74 +##! QUBIT Q=75 SHEET=QUBITS X=3.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 1) 75 +##! QUBIT Q=76 SHEET=QUBITS X=3 Y=2.5 COLOUR=gold +QUBIT_COORDS(3, 2.5) 76 +##! QUBIT Q=77 SHEET=QUBITS X=3.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 2) 77 +##! QUBIT Q=78 SHEET=QUBITS X=3 Y=3.5 COLOUR=gold +QUBIT_COORDS(3, 3.5) 78 +##! QUBIT Q=79 SHEET=QUBITS X=3.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 3) 79 +##! QUBIT Q=80 SHEET=QUBITS X=3 Y=4.5 COLOUR=gold +QUBIT_COORDS(3, 4.5) 80 +##! QUBIT Q=81 SHEET=QUBITS X=3.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 4) 81 +##! QUBIT Q=82 SHEET=QUBITS X=3 Y=5.5 COLOUR=gold +QUBIT_COORDS(3, 5.5) 82 +##! QUBIT Q=83 SHEET=QUBITS X=3.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 5) 83 +##! QUBIT Q=84 SHEET=QUBITS X=3 Y=6.5 COLOUR=gold +QUBIT_COORDS(3, 6.5) 84 +##! QUBIT Q=85 SHEET=QUBITS X=3.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 6) 85 +##! QUBIT Q=86 SHEET=QUBITS X=3 Y=7.5 COLOUR=gold +QUBIT_COORDS(3, 7.5) 86 +##! QUBIT Q=87 SHEET=QUBITS X=3.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 7) 87 +##! QUBIT Q=88 SHEET=QUBITS X=3 Y=8.5 COLOUR=gold +QUBIT_COORDS(3, 8.5) 88 +##! QUBIT Q=89 SHEET=QUBITS X=3.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 8) 89 +##! QUBIT Q=90 SHEET=QUBITS X=3 Y=9.5 COLOUR=gold +QUBIT_COORDS(3, 9.5) 90 +##! QUBIT Q=91 SHEET=QUBITS X=3.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 9) 91 +##! QUBIT Q=92 SHEET=QUBITS X=3 Y=10.5 COLOUR=gold +QUBIT_COORDS(3, 10.5) 92 +##! QUBIT Q=93 SHEET=QUBITS X=3.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 10) 93 +##! QUBIT Q=94 SHEET=QUBITS X=3 Y=11.5 COLOUR=gold +QUBIT_COORDS(3, 11.5) 94 +##! QUBIT Q=95 SHEET=QUBITS X=3.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(3.5, 11) 95 +##! QUBIT Q=96 SHEET=QUBITS X=4 Y=0.5 COLOUR=gold +QUBIT_COORDS(4, 0.5) 96 +##! QUBIT Q=97 SHEET=QUBITS X=4.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 0) 97 +##! QUBIT Q=98 SHEET=QUBITS X=4 Y=1.5 COLOUR=gold +QUBIT_COORDS(4, 1.5) 98 +##! QUBIT Q=99 SHEET=QUBITS X=4.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 1) 99 +##! QUBIT Q=100 SHEET=QUBITS X=4 Y=2.5 COLOUR=gold +QUBIT_COORDS(4, 2.5) 100 +##! QUBIT Q=101 SHEET=QUBITS X=4.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 2) 101 +##! QUBIT Q=102 SHEET=QUBITS X=4 Y=3.5 COLOUR=gold +QUBIT_COORDS(4, 3.5) 102 +##! QUBIT Q=103 SHEET=QUBITS X=4.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 3) 103 +##! QUBIT Q=104 SHEET=QUBITS X=4 Y=4.5 COLOUR=gold +QUBIT_COORDS(4, 4.5) 104 +##! QUBIT Q=105 SHEET=QUBITS X=4.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 4) 105 +##! QUBIT Q=106 SHEET=QUBITS X=4 Y=5.5 COLOUR=gold +QUBIT_COORDS(4, 5.5) 106 +##! QUBIT Q=107 SHEET=QUBITS X=4.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 5) 107 +##! QUBIT Q=108 SHEET=QUBITS X=4 Y=6.5 COLOUR=gold +QUBIT_COORDS(4, 6.5) 108 +##! QUBIT Q=109 SHEET=QUBITS X=4.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 6) 109 +##! QUBIT Q=110 SHEET=QUBITS X=4 Y=7.5 COLOUR=gold +QUBIT_COORDS(4, 7.5) 110 +##! QUBIT Q=111 SHEET=QUBITS X=4.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 7) 111 +##! QUBIT Q=112 SHEET=QUBITS X=4 Y=8.5 COLOUR=gold +QUBIT_COORDS(4, 8.5) 112 +##! QUBIT Q=113 SHEET=QUBITS X=4.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 8) 113 +##! QUBIT Q=114 SHEET=QUBITS X=4 Y=9.5 COLOUR=gold +QUBIT_COORDS(4, 9.5) 114 +##! QUBIT Q=115 SHEET=QUBITS X=4.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 9) 115 +##! QUBIT Q=116 SHEET=QUBITS X=4 Y=10.5 COLOUR=gold +QUBIT_COORDS(4, 10.5) 116 +##! QUBIT Q=117 SHEET=QUBITS X=4.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 10) 117 +##! QUBIT Q=118 SHEET=QUBITS X=4 Y=11.5 COLOUR=gold +QUBIT_COORDS(4, 11.5) 118 +##! QUBIT Q=119 SHEET=QUBITS X=4.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(4.5, 11) 119 +##! QUBIT Q=120 SHEET=QUBITS X=5 Y=0.5 COLOUR=gold +QUBIT_COORDS(5, 0.5) 120 +##! QUBIT Q=121 SHEET=QUBITS X=5.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 0) 121 +##! QUBIT Q=122 SHEET=QUBITS X=5 Y=1.5 COLOUR=gold +QUBIT_COORDS(5, 1.5) 122 +##! QUBIT Q=123 SHEET=QUBITS X=5.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 1) 123 +##! QUBIT Q=124 SHEET=QUBITS X=5 Y=2.5 COLOUR=gold +QUBIT_COORDS(5, 2.5) 124 +##! QUBIT Q=125 SHEET=QUBITS X=5.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 2) 125 +##! QUBIT Q=126 SHEET=QUBITS X=5 Y=3.5 COLOUR=gold +QUBIT_COORDS(5, 3.5) 126 +##! QUBIT Q=127 SHEET=QUBITS X=5.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 3) 127 +##! QUBIT Q=128 SHEET=QUBITS X=5 Y=4.5 COLOUR=gold +QUBIT_COORDS(5, 4.5) 128 +##! QUBIT Q=129 SHEET=QUBITS X=5.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 4) 129 +##! QUBIT Q=130 SHEET=QUBITS X=5 Y=5.5 COLOUR=gold +QUBIT_COORDS(5, 5.5) 130 +##! QUBIT Q=131 SHEET=QUBITS X=5.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 5) 131 +##! QUBIT Q=132 SHEET=QUBITS X=5 Y=6.5 COLOUR=gold +QUBIT_COORDS(5, 6.5) 132 +##! QUBIT Q=133 SHEET=QUBITS X=5.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 6) 133 +##! QUBIT Q=134 SHEET=QUBITS X=5 Y=7.5 COLOUR=gold +QUBIT_COORDS(5, 7.5) 134 +##! QUBIT Q=135 SHEET=QUBITS X=5.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 7) 135 +##! QUBIT Q=136 SHEET=QUBITS X=5 Y=8.5 COLOUR=gold +QUBIT_COORDS(5, 8.5) 136 +##! QUBIT Q=137 SHEET=QUBITS X=5.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 8) 137 +##! QUBIT Q=138 SHEET=QUBITS X=5 Y=9.5 COLOUR=gold +QUBIT_COORDS(5, 9.5) 138 +##! QUBIT Q=139 SHEET=QUBITS X=5.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 9) 139 +##! QUBIT Q=140 SHEET=QUBITS X=5 Y=10.5 COLOUR=gold +QUBIT_COORDS(5, 10.5) 140 +##! QUBIT Q=141 SHEET=QUBITS X=5.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 10) 141 +##! QUBIT Q=142 SHEET=QUBITS X=5 Y=11.5 COLOUR=gold +QUBIT_COORDS(5, 11.5) 142 +##! QUBIT Q=143 SHEET=QUBITS X=5.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(5.5, 11) 143 +##! QUBIT Q=144 SHEET=QUBITS X=6 Y=0.5 COLOUR=gold +QUBIT_COORDS(6, 0.5) 144 +##! QUBIT Q=145 SHEET=QUBITS X=6.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 0) 145 +##! QUBIT Q=146 SHEET=QUBITS X=6 Y=1.5 COLOUR=gold +QUBIT_COORDS(6, 1.5) 146 +##! QUBIT Q=147 SHEET=QUBITS X=6.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 1) 147 +##! QUBIT Q=148 SHEET=QUBITS X=6 Y=2.5 COLOUR=gold +QUBIT_COORDS(6, 2.5) 148 +##! QUBIT Q=149 SHEET=QUBITS X=6.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 2) 149 +##! QUBIT Q=150 SHEET=QUBITS X=6 Y=3.5 COLOUR=gold +QUBIT_COORDS(6, 3.5) 150 +##! QUBIT Q=151 SHEET=QUBITS X=6.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 3) 151 +##! QUBIT Q=152 SHEET=QUBITS X=6 Y=4.5 COLOUR=gold +QUBIT_COORDS(6, 4.5) 152 +##! QUBIT Q=153 SHEET=QUBITS X=6.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 4) 153 +##! QUBIT Q=154 SHEET=QUBITS X=6 Y=5.5 COLOUR=gold +QUBIT_COORDS(6, 5.5) 154 +##! QUBIT Q=155 SHEET=QUBITS X=6.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 5) 155 +##! QUBIT Q=156 SHEET=QUBITS X=6 Y=6.5 COLOUR=gold +QUBIT_COORDS(6, 6.5) 156 +##! QUBIT Q=157 SHEET=QUBITS X=6.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 6) 157 +##! QUBIT Q=158 SHEET=QUBITS X=6 Y=7.5 COLOUR=gold +QUBIT_COORDS(6, 7.5) 158 +##! QUBIT Q=159 SHEET=QUBITS X=6.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 7) 159 +##! QUBIT Q=160 SHEET=QUBITS X=6 Y=8.5 COLOUR=gold +QUBIT_COORDS(6, 8.5) 160 +##! QUBIT Q=161 SHEET=QUBITS X=6.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 8) 161 +##! QUBIT Q=162 SHEET=QUBITS X=6 Y=9.5 COLOUR=gold +QUBIT_COORDS(6, 9.5) 162 +##! QUBIT Q=163 SHEET=QUBITS X=6.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 9) 163 +##! QUBIT Q=164 SHEET=QUBITS X=6 Y=10.5 COLOUR=gold +QUBIT_COORDS(6, 10.5) 164 +##! QUBIT Q=165 SHEET=QUBITS X=6.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 10) 165 +##! HIGHLIGHT TARGET=QUBIT QUBITS=166 COLOR=red +##! QUBIT Q=166 SHEET=QUBITS X=6 Y=11.5 COLOUR=gold DEFECTIVE=true +QUBIT_COORDS(6, 11.5) 166 +##! QUBIT Q=167 SHEET=QUBITS X=6.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(6.5, 11) 167 +##! QUBIT Q=168 SHEET=QUBITS X=7 Y=0.5 COLOUR=gold +QUBIT_COORDS(7, 0.5) 168 +##! QUBIT Q=169 SHEET=QUBITS X=7.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 0) 169 +##! QUBIT Q=170 SHEET=QUBITS X=7 Y=1.5 COLOUR=gold +QUBIT_COORDS(7, 1.5) 170 +##! QUBIT Q=171 SHEET=QUBITS X=7.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 1) 171 +##! QUBIT Q=172 SHEET=QUBITS X=7 Y=2.5 COLOUR=gold +QUBIT_COORDS(7, 2.5) 172 +##! QUBIT Q=173 SHEET=QUBITS X=7.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 2) 173 +##! QUBIT Q=174 SHEET=QUBITS X=7 Y=3.5 COLOUR=gold +QUBIT_COORDS(7, 3.5) 174 +##! QUBIT Q=175 SHEET=QUBITS X=7.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 3) 175 +##! QUBIT Q=176 SHEET=QUBITS X=7 Y=4.5 COLOUR=gold +QUBIT_COORDS(7, 4.5) 176 +##! QUBIT Q=177 SHEET=QUBITS X=7.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 4) 177 +##! QUBIT Q=178 SHEET=QUBITS X=7 Y=5.5 COLOUR=gold +QUBIT_COORDS(7, 5.5) 178 +##! QUBIT Q=179 SHEET=QUBITS X=7.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 5) 179 +##! QUBIT Q=180 SHEET=QUBITS X=7 Y=6.5 COLOUR=gold +QUBIT_COORDS(7, 6.5) 180 +##! QUBIT Q=181 SHEET=QUBITS X=7.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 6) 181 +##! QUBIT Q=182 SHEET=QUBITS X=7 Y=7.5 COLOUR=gold +QUBIT_COORDS(7, 7.5) 182 +##! QUBIT Q=183 SHEET=QUBITS X=7.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 7) 183 +##! QUBIT Q=184 SHEET=QUBITS X=7 Y=8.5 COLOUR=gold +QUBIT_COORDS(7, 8.5) 184 +##! QUBIT Q=185 SHEET=QUBITS X=7.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 8) 185 +##! QUBIT Q=186 SHEET=QUBITS X=7 Y=9.5 COLOUR=gold +QUBIT_COORDS(7, 9.5) 186 +##! QUBIT Q=187 SHEET=QUBITS X=7.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 9) 187 +##! QUBIT Q=188 SHEET=QUBITS X=7 Y=10.5 COLOUR=gold +QUBIT_COORDS(7, 10.5) 188 +##! QUBIT Q=189 SHEET=QUBITS X=7.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 10) 189 +##! QUBIT Q=190 SHEET=QUBITS X=7 Y=11.5 COLOUR=gold +QUBIT_COORDS(7, 11.5) 190 +##! QUBIT Q=191 SHEET=QUBITS X=7.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(7.5, 11) 191 +##! QUBIT Q=192 SHEET=QUBITS X=8 Y=0.5 COLOUR=gold +QUBIT_COORDS(8, 0.5) 192 +##! QUBIT Q=193 SHEET=QUBITS X=8.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 0) 193 +##! QUBIT Q=194 SHEET=QUBITS X=8 Y=1.5 COLOUR=gold +QUBIT_COORDS(8, 1.5) 194 +##! QUBIT Q=195 SHEET=QUBITS X=8.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 1) 195 +##! QUBIT Q=196 SHEET=QUBITS X=8 Y=2.5 COLOUR=gold +QUBIT_COORDS(8, 2.5) 196 +##! QUBIT Q=197 SHEET=QUBITS X=8.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 2) 197 +##! QUBIT Q=198 SHEET=QUBITS X=8 Y=3.5 COLOUR=gold +QUBIT_COORDS(8, 3.5) 198 +##! QUBIT Q=199 SHEET=QUBITS X=8.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 3) 199 +##! QUBIT Q=200 SHEET=QUBITS X=8 Y=4.5 COLOUR=gold +QUBIT_COORDS(8, 4.5) 200 +##! QUBIT Q=201 SHEET=QUBITS X=8.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 4) 201 +##! QUBIT Q=202 SHEET=QUBITS X=8 Y=5.5 COLOUR=gold +QUBIT_COORDS(8, 5.5) 202 +##! QUBIT Q=203 SHEET=QUBITS X=8.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 5) 203 +##! QUBIT Q=204 SHEET=QUBITS X=8 Y=6.5 COLOUR=gold +QUBIT_COORDS(8, 6.5) 204 +##! QUBIT Q=205 SHEET=QUBITS X=8.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 6) 205 +##! QUBIT Q=206 SHEET=QUBITS X=8 Y=7.5 COLOUR=gold +QUBIT_COORDS(8, 7.5) 206 +##! QUBIT Q=207 SHEET=QUBITS X=8.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 7) 207 +##! QUBIT Q=208 SHEET=QUBITS X=8 Y=8.5 COLOUR=gold +QUBIT_COORDS(8, 8.5) 208 +##! QUBIT Q=209 SHEET=QUBITS X=8.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 8) 209 +##! QUBIT Q=210 SHEET=QUBITS X=8 Y=9.5 COLOUR=gold +QUBIT_COORDS(8, 9.5) 210 +##! QUBIT Q=211 SHEET=QUBITS X=8.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 9) 211 +##! QUBIT Q=212 SHEET=QUBITS X=8 Y=10.5 COLOUR=gold +QUBIT_COORDS(8, 10.5) 212 +##! QUBIT Q=213 SHEET=QUBITS X=8.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 10) 213 +##! QUBIT Q=214 SHEET=QUBITS X=8 Y=11.5 COLOUR=gold +QUBIT_COORDS(8, 11.5) 214 +##! QUBIT Q=215 SHEET=QUBITS X=8.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(8.5, 11) 215 +##! QUBIT Q=216 SHEET=QUBITS X=9 Y=0.5 COLOUR=gold +QUBIT_COORDS(9, 0.5) 216 +##! QUBIT Q=217 SHEET=QUBITS X=9.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 0) 217 +##! QUBIT Q=218 SHEET=QUBITS X=9 Y=1.5 COLOUR=gold +QUBIT_COORDS(9, 1.5) 218 +##! QUBIT Q=219 SHEET=QUBITS X=9.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 1) 219 +##! QUBIT Q=220 SHEET=QUBITS X=9 Y=2.5 COLOUR=gold +QUBIT_COORDS(9, 2.5) 220 +##! QUBIT Q=221 SHEET=QUBITS X=9.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 2) 221 +##! QUBIT Q=222 SHEET=QUBITS X=9 Y=3.5 COLOUR=gold +QUBIT_COORDS(9, 3.5) 222 +##! QUBIT Q=223 SHEET=QUBITS X=9.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 3) 223 +##! QUBIT Q=224 SHEET=QUBITS X=9 Y=4.5 COLOUR=gold +QUBIT_COORDS(9, 4.5) 224 +##! QUBIT Q=225 SHEET=QUBITS X=9.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 4) 225 +##! QUBIT Q=226 SHEET=QUBITS X=9 Y=5.5 COLOUR=gold +QUBIT_COORDS(9, 5.5) 226 +##! QUBIT Q=227 SHEET=QUBITS X=9.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 5) 227 +##! QUBIT Q=228 SHEET=QUBITS X=9 Y=6.5 COLOUR=gold +QUBIT_COORDS(9, 6.5) 228 +##! QUBIT Q=229 SHEET=QUBITS X=9.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 6) 229 +##! QUBIT Q=230 SHEET=QUBITS X=9 Y=7.5 COLOUR=gold +QUBIT_COORDS(9, 7.5) 230 +##! QUBIT Q=231 SHEET=QUBITS X=9.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 7) 231 +##! QUBIT Q=232 SHEET=QUBITS X=9 Y=8.5 COLOUR=gold +QUBIT_COORDS(9, 8.5) 232 +##! QUBIT Q=233 SHEET=QUBITS X=9.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 8) 233 +##! QUBIT Q=234 SHEET=QUBITS X=9 Y=9.5 COLOUR=gold +QUBIT_COORDS(9, 9.5) 234 +##! QUBIT Q=235 SHEET=QUBITS X=9.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 9) 235 +##! QUBIT Q=236 SHEET=QUBITS X=9 Y=10.5 COLOUR=gold +QUBIT_COORDS(9, 10.5) 236 +##! QUBIT Q=237 SHEET=QUBITS X=9.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 10) 237 +##! QUBIT Q=238 SHEET=QUBITS X=9 Y=11.5 COLOUR=gold +QUBIT_COORDS(9, 11.5) 238 +##! QUBIT Q=239 SHEET=QUBITS X=9.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(9.5, 11) 239 +##! QUBIT Q=240 SHEET=QUBITS X=10 Y=0.5 COLOUR=gold +QUBIT_COORDS(10, 0.5) 240 +##! QUBIT Q=241 SHEET=QUBITS X=10.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 0) 241 +##! QUBIT Q=242 SHEET=QUBITS X=10 Y=1.5 COLOUR=gold +QUBIT_COORDS(10, 1.5) 242 +##! QUBIT Q=243 SHEET=QUBITS X=10.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 1) 243 +##! QUBIT Q=244 SHEET=QUBITS X=10 Y=2.5 COLOUR=gold +QUBIT_COORDS(10, 2.5) 244 +##! QUBIT Q=245 SHEET=QUBITS X=10.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 2) 245 +##! QUBIT Q=246 SHEET=QUBITS X=10 Y=3.5 COLOUR=gold +QUBIT_COORDS(10, 3.5) 246 +##! QUBIT Q=247 SHEET=QUBITS X=10.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 3) 247 +##! QUBIT Q=248 SHEET=QUBITS X=10 Y=4.5 COLOUR=gold +QUBIT_COORDS(10, 4.5) 248 +##! QUBIT Q=249 SHEET=QUBITS X=10.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 4) 249 +##! QUBIT Q=250 SHEET=QUBITS X=10 Y=5.5 COLOUR=gold +QUBIT_COORDS(10, 5.5) 250 +##! QUBIT Q=251 SHEET=QUBITS X=10.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 5) 251 +##! QUBIT Q=252 SHEET=QUBITS X=10 Y=6.5 COLOUR=gold +QUBIT_COORDS(10, 6.5) 252 +##! QUBIT Q=253 SHEET=QUBITS X=10.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 6) 253 +##! QUBIT Q=254 SHEET=QUBITS X=10 Y=7.5 COLOUR=gold +QUBIT_COORDS(10, 7.5) 254 +##! QUBIT Q=255 SHEET=QUBITS X=10.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 7) 255 +##! QUBIT Q=256 SHEET=QUBITS X=10 Y=8.5 COLOUR=gold +QUBIT_COORDS(10, 8.5) 256 +##! QUBIT Q=257 SHEET=QUBITS X=10.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 8) 257 +##! QUBIT Q=258 SHEET=QUBITS X=10 Y=9.5 COLOUR=gold +QUBIT_COORDS(10, 9.5) 258 +##! QUBIT Q=259 SHEET=QUBITS X=10.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 9) 259 +##! QUBIT Q=260 SHEET=QUBITS X=10 Y=10.5 COLOUR=gold +QUBIT_COORDS(10, 10.5) 260 +##! QUBIT Q=261 SHEET=QUBITS X=10.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 10) 261 +##! QUBIT Q=262 SHEET=QUBITS X=10 Y=11.5 COLOUR=gold +QUBIT_COORDS(10, 11.5) 262 +##! QUBIT Q=263 SHEET=QUBITS X=10.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(10.5, 11) 263 +##! QUBIT Q=264 SHEET=QUBITS X=11 Y=0.5 COLOUR=gold +QUBIT_COORDS(11, 0.5) 264 +##! QUBIT Q=265 SHEET=QUBITS X=11.5 Y=0 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 0) 265 +##! QUBIT Q=266 SHEET=QUBITS X=11 Y=1.5 COLOUR=gold +QUBIT_COORDS(11, 1.5) 266 +##! QUBIT Q=267 SHEET=QUBITS X=11.5 Y=1 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 1) 267 +##! QUBIT Q=268 SHEET=QUBITS X=11 Y=2.5 COLOUR=gold +QUBIT_COORDS(11, 2.5) 268 +##! QUBIT Q=269 SHEET=QUBITS X=11.5 Y=2 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 2) 269 +##! QUBIT Q=270 SHEET=QUBITS X=11 Y=3.5 COLOUR=gold +QUBIT_COORDS(11, 3.5) 270 +##! QUBIT Q=271 SHEET=QUBITS X=11.5 Y=3 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 3) 271 +##! QUBIT Q=272 SHEET=QUBITS X=11 Y=4.5 COLOUR=gold +QUBIT_COORDS(11, 4.5) 272 +##! QUBIT Q=273 SHEET=QUBITS X=11.5 Y=4 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 4) 273 +##! QUBIT Q=274 SHEET=QUBITS X=11 Y=5.5 COLOUR=gold +QUBIT_COORDS(11, 5.5) 274 +##! QUBIT Q=275 SHEET=QUBITS X=11.5 Y=5 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 5) 275 +##! QUBIT Q=276 SHEET=QUBITS X=11 Y=6.5 COLOUR=gold +QUBIT_COORDS(11, 6.5) 276 +##! QUBIT Q=277 SHEET=QUBITS X=11.5 Y=6 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 6) 277 +##! QUBIT Q=278 SHEET=QUBITS X=11 Y=7.5 COLOUR=gold +QUBIT_COORDS(11, 7.5) 278 +##! QUBIT Q=279 SHEET=QUBITS X=11.5 Y=7 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 7) 279 +##! QUBIT Q=280 SHEET=QUBITS X=11 Y=8.5 COLOUR=gold +QUBIT_COORDS(11, 8.5) 280 +##! QUBIT Q=281 SHEET=QUBITS X=11.5 Y=8 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 8) 281 +##! QUBIT Q=282 SHEET=QUBITS X=11 Y=9.5 COLOUR=gold +QUBIT_COORDS(11, 9.5) 282 +##! QUBIT Q=283 SHEET=QUBITS X=11.5 Y=9 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 9) 283 +##! QUBIT Q=284 SHEET=QUBITS X=11 Y=10.5 COLOUR=gold +QUBIT_COORDS(11, 10.5) 284 +##! QUBIT Q=285 SHEET=QUBITS X=11.5 Y=10 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 10) 285 +##! QUBIT Q=286 SHEET=QUBITS X=11 Y=11.5 COLOUR=gold +QUBIT_COORDS(11, 11.5) 286 +##! QUBIT Q=287 SHEET=QUBITS X=11.5 Y=11 COLOUR=mediumseagreen +QUBIT_COORDS(11.5, 11) 287 +##! CONN SET SHEET=A2 EDGES=(0-15,2-17,4-19,6-21,8-23,10-1,12-3,14-5,16-7,18-9,20-11,22-13,24-39,26-41,28-43,30-45,32-47,34-25,36-27,38-29,40-31,42-33,44-35,46-37,48-63,50-65,52-67,54-69,56-71,58-49,60-51,62-53,64-55,66-57,68-59,70-61,72-87,74-89,76-91,78-93,80-95,82-73,84-75,86-77,88-79,90-81,92-83,94-85,96-111,98-113,100-115,102-117,104-119,106-97,108-99,110-101,112-103,114-105,116-107,118-109,120-135,122-137,124-139,126-141,128-143,130-121,132-123,134-125,136-127,138-129,140-131,142-133,144-159,146-161,148-163,150-165,152-167,154-145,156-147,158-149,160-151,162-153,164-155,166-157,168-183,170-185,172-187,174-189,176-191,178-169,180-171,182-173,184-175,186-177,188-179,190-181,192-207,194-209,196-211,198-213,200-215,202-193,204-195,206-197,208-199,210-201,212-203,214-205,216-231,218-233,220-235,222-237,224-239,226-217,228-219,230-221,232-223,234-225,236-227,238-229,240-255,242-257,244-259,246-261,248-263,250-241,252-243,254-245,256-247,258-249,260-251,262-253,264-279,266-281,268-283,270-285,272-287,274-265,276-267,278-269,280-271,282-273,284-275,286-277) THICKNESS=2 COLOUR=#4361ee +##! CONN SET SHEET=A2B2^-1 EDGES=(0-279,2-281,4-283,6-285,8-287,10-265,12-267,14-269,16-271,18-273,20-275,22-277,24-15,26-17,28-19,30-21,32-23,34-1,36-3,38-5,40-7,42-9,44-11,46-13,48-39,50-41,52-43,54-45,56-47,58-25,60-27,62-29,64-31,66-33,68-35,70-37,72-63,74-65,76-67,78-69,80-71,82-49,84-51,86-53,88-55,90-57,92-59,94-61,96-87,98-89,100-91,102-93,104-95,106-73,108-75,110-77,112-79,114-81,116-83,118-85,120-111,122-113,124-115,126-117,128-119,130-97,132-99,134-101,136-103,138-105,140-107,142-109,144-135,146-137,148-139,150-141,152-143,154-121,156-123,158-125,160-127,162-129,164-131,166-133,168-159,170-161,172-163,174-165,176-167,178-145,180-147,182-149,184-151,186-153,188-155,190-157,192-183,194-185,196-187,198-189,200-191,202-169,204-171,206-173,208-175,210-177,212-179,214-181,216-207,218-209,220-211,222-213,224-215,226-193,228-195,230-197,232-199,234-201,236-203,238-205,240-231,242-233,244-235,246-237,248-239,250-217,252-219,254-221,256-223,258-225,260-227,262-229,264-255,266-257,268-259,270-261,272-263,274-241,276-243,278-245,280-247,282-249,284-251,286-253) THICKNESS=2 COLOUR=#2a9d8f +##! CONN SET SHEET=A3 EDGES=(0-221,2-223,4-225,6-227,8-229,10-231,12-233,14-235,16-237,18-239,20-217,22-219,24-245,26-247,28-249,30-251,32-253,34-255,36-257,38-259,40-261,42-263,44-241,46-243,48-269,50-271,52-273,54-275,56-277,58-279,60-281,62-283,64-285,66-287,68-265,70-267,72-5,74-7,76-9,78-11,80-13,82-15,84-17,86-19,88-21,90-23,92-1,94-3,96-29,98-31,100-33,102-35,104-37,106-39,108-41,110-43,112-45,114-47,116-25,118-27,120-53,122-55,124-57,126-59,128-61,130-63,132-65,134-67,136-69,138-71,140-49,142-51,144-77,146-79,148-81,150-83,152-85,154-87,156-89,158-91,160-93,162-95,164-73,166-75,168-101,170-103,172-105,174-107,176-109,178-111,180-113,182-115,184-117,186-119,188-97,190-99,192-125,194-127,196-129,198-131,200-133,202-135,204-137,206-139,208-141,210-143,212-121,214-123,216-149,218-151,220-153,222-155,224-157,226-159,228-161,230-163,232-165,234-167,236-145,238-147,240-173,242-175,244-177,246-179,248-181,250-183,252-185,254-187,256-189,258-191,260-169,262-171,264-197,266-199,268-201,270-203,272-205,274-207,276-209,278-211,280-213,282-215,284-193,286-195) THICKNESS=2 COLOUR=#e76f51 +##! CONN SET SHEET=A3B3^-1 EDGES=(0-179,2-181,4-183,6-185,8-187,10-189,12-191,14-169,16-171,18-173,20-175,22-177,24-203,26-205,28-207,30-209,32-211,34-213,36-215,38-193,40-195,42-197,44-199,46-201,48-227,50-229,52-231,54-233,56-235,58-237,60-239,62-217,64-219,66-221,68-223,70-225,72-251,74-253,76-255,78-257,80-259,82-261,84-263,86-241,88-243,90-245,92-247,94-249,96-275,98-277,100-279,102-281,104-283,106-285,108-287,110-265,112-267,114-269,116-271,118-273,120-11,122-13,124-15,126-17,128-19,130-21,132-23,134-1,136-3,138-5,140-7,142-9,144-35,146-37,148-39,150-41,152-43,154-45,156-47,158-25,160-27,162-29,164-31,166-33,168-59,170-61,172-63,174-65,176-67,178-69,180-71,182-49,184-51,186-53,188-55,190-57,192-83,194-85,196-87,198-89,200-91,202-93,204-95,206-73,208-75,210-77,212-79,214-81,216-107,218-109,220-111,222-113,224-115,226-117,228-119,230-97,232-99,234-101,236-103,238-105,240-131,242-133,244-135,246-137,248-139,250-141,252-143,254-121,256-123,258-125,260-127,262-129,264-155,266-157,268-159,270-161,272-163,274-165,276-167,278-145,280-147,282-149,284-151,286-153) THICKNESS=2 COLOUR=#f4a261 +##! CONN SET SHEET=B2 EDGES=(0-265,2-267,4-269,6-271,8-273,10-275,12-277,14-279,16-281,18-283,20-285,22-287,24-1,26-3,28-5,30-7,32-9,34-11,36-13,38-15,40-17,42-19,44-21,46-23,48-25,50-27,52-29,54-31,56-33,58-35,60-37,62-39,64-41,66-43,68-45,70-47,72-49,74-51,76-53,78-55,80-57,82-59,84-61,86-63,88-65,90-67,92-69,94-71,96-73,98-75,100-77,102-79,104-81,106-83,108-85,110-87,112-89,114-91,116-93,118-95,120-97,122-99,124-101,126-103,128-105,130-107,132-109,134-111,136-113,138-115,140-117,142-119,144-121,146-123,148-125,150-127,152-129,154-131,156-133,158-135,160-137,162-139,164-141,166-143,168-145,170-147,172-149,174-151,176-153,178-155,180-157,182-159,184-161,186-163,188-165,190-167,192-169,194-171,196-173,198-175,200-177,202-179,204-181,206-183,208-185,210-187,212-189,214-191,216-193,218-195,220-197,222-199,224-201,226-203,228-205,230-207,232-209,234-211,236-213,238-215,240-217,242-219,244-221,246-223,248-225,250-227,252-229,254-231,256-233,258-235,260-237,262-239,264-241,266-243,268-245,270-247,272-249,274-251,276-253,278-255,280-257,282-259,284-261,286-263) THICKNESS=2 COLOUR=#e9c46a +##! CONN SET SHEET=B3 EDGES=(0-247,2-249,4-251,6-253,8-255,10-257,12-259,14-261,16-263,18-241,20-243,22-245,24-271,26-273,28-275,30-277,32-279,34-281,36-283,38-285,40-287,42-265,44-267,46-269,48-7,50-9,52-11,54-13,56-15,58-17,60-19,62-21,64-23,66-1,68-3,70-5,72-31,74-33,76-35,78-37,80-39,82-41,84-43,86-45,88-47,90-25,92-27,94-29,96-55,98-57,100-59,102-61,104-63,106-65,108-67,110-69,112-71,114-49,116-51,118-53,120-79,122-81,124-83,126-85,128-87,130-89,132-91,134-93,136-95,138-73,140-75,142-77,144-103,146-105,148-107,150-109,152-111,154-113,156-115,158-117,160-119,162-97,164-99,166-101,168-127,170-129,172-131,174-133,176-135,178-137,180-139,182-141,184-143,186-121,188-123,190-125,192-151,194-153,196-155,198-157,200-159,202-161,204-163,206-165,208-167,210-145,212-147,214-149,216-175,218-177,220-179,222-181,224-183,226-185,228-187,230-189,232-191,234-169,236-171,238-173,240-199,242-201,244-203,246-205,248-207,250-209,252-211,254-213,256-215,258-193,260-195,262-197,264-223,266-225,268-227,270-229,272-231,274-233,276-235,278-237,280-239,282-217,284-219,286-221) THICKNESS=2 COLOUR=#8a5cff +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 10 92 247 265 1 0 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 12 94 249 267 3 2 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 14 251 269 72 5 4 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 16 253 271 74 7 6 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 18 255 273 76 9 8 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 20 257 275 78 11 10 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 22 259 277 80 13 12 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 15 14 261 279 0 82 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 17 16 263 281 2 84 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 19 18 86 283 241 4 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 21 20 88 285 243 6 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 23 22 90 287 245 8 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 34 116 271 25 24 1 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 36 118 273 27 26 3 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 38 275 96 29 5 28 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 40 277 98 31 7 30 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 42 279 100 33 9 32 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 44 281 102 35 11 34 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 46 283 104 37 13 36 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 15 39 38 285 106 24 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 17 41 40 287 108 26 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 19 42 43 110 265 28 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 21 44 45 112 267 30 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 23 46 47 114 269 32 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 58 140 49 48 25 7 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 60 142 51 50 27 9 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 11 62 120 53 52 29 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 13 64 122 55 54 31 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 15 66 124 57 56 33 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 17 68 126 59 58 35 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 19 70 128 61 60 37 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 39 21 62 63 130 48 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 41 23 64 65 132 50 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 43 66 67 134 52 1 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 45 68 69 136 54 3 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 47 70 71 138 56 5 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 82 164 73 72 49 31 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 35 86 144 77 76 53 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 37 88 146 79 78 55 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 39 90 148 81 80 57 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 41 92 150 83 82 59 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 43 94 152 85 84 61 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 63 45 86 87 154 72 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 65 47 88 89 156 74 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 67 90 91 158 76 25 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 69 92 93 160 78 27 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 71 94 95 162 80 29 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 106 188 97 96 73 55 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 108 190 99 98 75 57 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 59 110 168 101 100 77 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 61 112 170 103 102 79 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 63 114 172 105 104 81 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 65 116 174 107 106 83 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 67 118 176 109 108 85 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 87 69 110 111 178 96 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 89 71 112 113 180 98 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 91 114 115 182 100 49 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 93 116 117 184 102 51 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 95 118 119 186 104 53 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 130 212 121 120 97 79 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 132 214 123 122 99 81 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 83 134 192 125 124 101 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 85 136 194 127 126 103 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 87 138 196 129 128 105 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 89 140 198 131 130 107 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 91 142 200 133 132 109 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 111 93 134 135 202 120 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 113 95 136 137 204 122 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 115 138 139 206 124 73 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 117 140 141 208 126 75 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 119 142 143 210 128 77 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 154 236 145 144 121 103 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 156 238 147 146 123 105 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 107 158 216 149 148 125 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 109 160 218 151 150 127 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 111 162 220 153 152 129 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 113 164 222 155 154 131 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 135 117 158 159 226 144 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 137 119 160 161 228 146 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 139 162 163 230 148 97 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 141 164 165 232 150 99 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 178 260 169 168 145 127 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 180 262 171 170 147 129 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 131 182 240 173 172 149 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 133 184 242 175 174 151 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 135 186 244 177 176 153 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 137 188 246 179 178 155 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 139 190 248 181 180 157 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 159 141 182 183 250 168 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 161 143 184 185 252 170 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 163 186 187 254 172 121 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 165 188 189 256 174 123 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 167 190 191 258 176 125 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 202 284 193 192 169 151 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 204 286 195 194 171 153 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 155 206 264 197 196 173 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 157 208 266 199 198 175 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 159 210 268 201 200 177 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 161 212 270 203 202 179 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 163 214 272 205 204 181 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 183 165 206 207 274 192 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 185 167 208 209 276 194 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 187 210 211 278 196 145 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 189 212 213 280 198 147 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 191 214 215 282 200 149 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 20 226 175 217 216 193 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 22 228 177 219 218 195 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 179 230 220 221 197 0 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 181 232 222 223 199 2 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 183 234 224 225 201 4 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 185 236 226 227 203 6 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 187 238 228 229 205 8 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 189 230 207 231 216 10 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 191 232 209 233 218 12 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 14 211 234 235 220 169 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 16 213 236 237 222 171 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 18 215 238 239 224 173 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 44 250 199 241 240 217 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 46 252 201 243 242 219 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 203 254 244 245 221 24 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 205 256 246 247 223 26 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 207 258 248 249 225 28 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 209 260 250 251 227 30 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 211 262 252 253 229 32 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 213 254 231 255 240 34 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 215 256 233 257 242 36 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 38 235 258 259 244 193 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 40 237 260 261 246 195 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 42 239 262 263 248 197 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 68 274 223 265 264 241 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 70 276 225 267 266 243 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 227 278 268 269 245 48 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 229 280 270 271 247 50 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 231 282 272 273 249 52 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 233 284 274 275 251 54 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 235 286 276 277 253 56 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 237 278 255 279 264 58 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 239 280 257 281 266 60 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 62 259 282 283 268 217 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 64 261 284 285 270 219 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 66 263 286 287 272 221 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 15 66 221 24 1 0 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 17 68 223 26 3 2 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 19 70 225 28 5 4 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 21 227 48 7 30 6 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 23 229 50 9 32 8 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 11 10 34 231 52 1 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 13 12 36 233 54 3 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 15 14 38 235 56 5 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 17 16 40 237 58 7 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 19 18 42 239 60 9 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 62 20 21 44 217 11 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 64 22 23 46 219 13 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 39 90 245 48 25 24 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 41 92 247 50 27 26 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 43 94 249 52 29 28 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 45 251 72 31 54 30 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 47 253 74 33 56 32 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 35 34 58 255 76 25 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 37 36 60 257 78 27 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 39 38 62 259 80 29 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 41 40 64 261 82 31 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 43 42 66 263 84 33 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 86 44 45 68 241 35 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 88 46 47 70 243 37 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 63 114 269 72 49 48 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 65 116 271 74 51 50 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 67 118 273 76 53 52 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 69 275 96 55 78 54 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 71 277 98 57 80 56 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 59 58 82 279 100 49 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 61 60 84 281 102 51 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 63 62 86 283 104 53 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 65 64 88 285 106 55 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 67 66 90 287 108 57 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 110 68 69 92 265 59 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 112 70 71 94 267 61 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 87 138 96 73 72 5 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 89 140 98 75 74 7 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 91 142 100 77 76 9 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 11 93 102 120 79 78 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 13 95 104 122 81 80 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 15 82 83 106 124 73 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 17 84 85 108 126 75 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 19 86 87 110 128 77 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 21 88 89 112 130 79 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 23 90 91 114 132 81 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 92 93 116 134 83 1 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 94 95 118 136 85 3 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 111 162 120 97 96 29 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 113 164 122 99 98 31 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 35 117 126 144 103 102 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 37 119 128 146 105 104 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 39 106 107 130 148 97 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 41 108 109 132 150 99 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 43 110 111 134 152 101 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 45 112 113 136 154 103 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 47 114 115 138 156 105 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 116 117 140 158 107 25 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 118 119 142 160 109 27 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 135 186 144 121 120 53 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 137 188 146 123 122 55 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 139 190 148 125 124 57 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 59 141 150 168 127 126 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 61 143 152 170 129 128 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 63 130 131 154 172 121 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 65 132 133 156 174 123 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 67 134 135 158 176 125 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 69 136 137 160 178 127 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 71 138 139 162 180 129 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 140 141 164 182 131 49 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 159 210 168 145 144 77 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 161 212 170 147 146 79 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 163 214 172 149 148 81 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 83 165 174 192 151 150 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 85 167 176 194 153 152 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 87 154 155 178 196 145 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 89 156 157 180 198 147 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 91 158 159 182 200 149 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 93 160 161 184 202 151 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 95 162 163 186 204 153 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 164 165 188 206 155 73 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 183 234 192 169 168 101 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 185 236 194 171 170 103 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 187 238 196 173 172 105 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 107 189 198 216 175 174 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 109 191 200 218 177 176 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 111 178 179 202 220 169 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 113 180 181 204 222 171 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 115 182 183 206 224 173 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 117 184 185 208 226 175 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 119 186 187 210 228 177 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 188 189 212 230 179 97 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 190 191 214 232 181 99 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 207 258 216 193 192 125 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 209 260 218 195 194 127 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 211 262 220 197 196 129 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 131 213 222 240 199 198 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 133 215 224 242 201 200 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 135 202 203 226 244 193 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 137 204 205 228 246 195 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 139 206 207 230 248 197 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 141 208 209 232 250 199 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 143 210 211 234 252 201 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 212 213 236 254 203 121 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 214 215 238 256 205 123 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 231 282 240 217 216 149 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 233 284 242 219 218 151 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 235 286 244 221 220 153 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 155 237 246 264 223 222 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 157 239 248 266 225 224 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 159 226 227 250 268 217 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 161 228 229 252 270 219 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 163 230 231 254 272 221 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 165 232 233 256 274 223 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 167 234 235 258 276 225 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 236 237 260 278 227 145 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 238 239 262 280 229 147 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 18 255 264 241 240 173 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 20 257 266 243 242 175 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 22 259 268 245 244 177 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 179 261 270 246 247 0 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 181 263 272 248 249 2 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 183 250 274 251 241 4 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 185 252 276 253 243 6 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 187 254 278 255 245 8 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 189 256 280 257 247 10 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 191 258 282 259 249 12 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 14 260 261 284 251 169 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 16 262 263 286 253 171 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 42 279 264 265 197 0 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 44 281 266 267 199 2 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 46 283 268 269 201 4 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 285 203 270 271 24 6 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 287 205 272 273 26 8 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 10 207 274 275 265 28 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 12 209 276 277 267 30 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 14 211 278 279 269 32 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 16 213 280 281 271 34 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 18 215 282 283 273 36 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 38 20 284 285 275 193 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 40 22 286 287 277 195 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 33 84 75 74 51 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 156 115 224 157 133 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 143 167 234 152 101 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 33 115 124 101 100 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 142 143 184 133 51 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 167 190 208 157 75 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 84 115 133 156 157 224 75 74 51 33 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 84 143 167 234 152 101 75 74 51 33 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 115 142 143 184 133 124 101 100 51 33 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 115 167 190 208 157 124 101 100 75 33 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 33 84 75 74 51 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 33 115 124 101 100 +##! HIGHLIGHT TARGET=QUBIT QUBITS=166 COLOR=red +CX 175 184 84 75 233 54 174 151 5 138 144 159 264 279 48 63 156 133 80 95 97 230 172 187 89 198 234 101 193 38 125 258 68 59 29 162 85 194 104 119 123 132 121 254 64 55 21 130 221 66 141 250 181 2 113 222 17 126 276 267 249 94 92 83 109 218 212 203 13 122 88 79 240 255 56 71 73 206 237 58 268 283 52 67 93 202 9 142 129 262 205 26 169 14 260 251 44 35 61 170 164 155 200 215 197 42 256 247 40 31 36 27 189 10 225 70 281 102 284 275 188 179 81 214 277 98 280 271 77 210 248 263 49 182 213 34 244 259 28 43 148 163 209 30 105 238 120 135 24 39 177 22 236 227 37 146 140 131 269 114 272 287 176 191 173 18 232 223 16 7 136 127 265 110 108 99 228 219 12 3 285 106 201 46 253 74 53 186 128 143 145 278 32 47 220 235 4 19 124 139 216 231 0 15 273 118 20 11 165 274 69 178 112 103 241 86 161 270 204 195 261 82 1 134 76 91 257 78 229 50 168 183 72 87 8 23 153 286 57 190 196 211 100 115 208 185 149 282 60 51 192 207 96 111 25 158 45 154 245 90 217 62 137 246 41 150 180 171 +TICK +CX 54 13 262 197 2 249 199 232 103 136 258 193 22 245 162 97 75 108 195 228 227 260 11 44 222 181 185 226 126 85 183 192 46 269 119 128 62 21 278 237 118 53 250 209 154 113 210 145 58 17 114 49 147 180 246 205 10 257 51 84 6 253 279 0 142 77 138 73 171 204 34 281 203 236 107 140 102 61 242 175 194 153 191 200 98 57 95 104 254 213 214 149 267 12 187 196 130 89 91 100 90 25 63 72 283 4 14 261 55 88 238 173 243 276 184 117 47 56 110 69 179 212 83 116 139 148 43 52 202 161 38 285 79 112 167 234 135 144 78 37 39 48 170 129 133 174 74 33 71 80 271 16 163 172 67 76 282 217 186 121 255 264 132 65 159 168 35 68 134 93 224 157 94 29 127 160 31 64 287 8 27 60 239 248 59 92 235 244 19 28 111 120 270 229 231 240 15 24 206 165 146 105 266 225 50 9 263 272 82 41 259 268 275 20 30 277 131 164 230 189 286 221 70 5 26 273 190 125 115 156 223 256 7 40 66 1 219 252 3 36 18 241 218 177 122 81 251 284 155 188 211 220 152 143 247 280 87 96 207 216 23 32 182 141 86 45 42 265 274 233 178 137 +TICK +CX 118 95 273 8 178 155 270 247 54 31 5 28 20 285 266 243 50 27 97 120 2 267 1 24 224 115 189 212 93 116 33 56 125 148 245 268 29 52 217 240 222 199 121 144 126 103 272 249 186 163 213 236 218 195 62 39 94 71 214 191 154 131 58 35 246 223 197 220 6 271 73 96 193 216 165 188 69 92 221 244 37 60 102 79 117 226 194 171 98 75 70 47 34 11 282 259 66 43 77 100 250 227 152 167 14 279 255 278 251 274 10 275 261 284 45 68 65 174 137 160 257 280 41 64 229 252 9 32 265 0 74 51 231 254 262 239 12 277 258 235 42 19 162 139 134 111 38 15 85 108 130 107 177 200 81 104 18 283 141 164 173 196 113 136 233 256 17 40 49 72 205 228 210 187 114 91 13 36 206 183 105 128 110 87 82 59 242 133 202 179 142 119 269 4 46 23 78 55 170 147 230 207 16 281 61 84 181 204 263 286 22 287 57 80 89 112 149 172 53 76 241 264 25 48 30 7 145 168 90 67 237 260 21 44 26 3 182 159 86 63 +TICK +MX 2 6 10 14 18 22 26 30 34 38 42 46 50 54 58 62 66 70 74 78 82 86 90 94 98 102 110 114 118 126 130 134 142 152 154 162 170 178 182 186 194 202 206 210 214 218 222 224 230 231 242 246 250 251 255 258 262 263 266 270 282 +MZ 0 4 8 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 92 96 100 104 108 112 116 120 128 136 144 148 160 164 168 172 174 188 196 200 204 212 216 220 226 228 236 240 244 249 252 256 260 264 268 277 280 281 284 285 +TICK +RX 2 6 10 14 18 22 26 30 34 38 42 46 50 54 58 62 66 70 74 78 82 86 90 94 98 102 110 114 118 126 130 134 142 152 154 162 170 178 182 186 194 202 206 210 214 218 222 224 230 231 242 246 250 251 255 258 262 263 266 270 282 +R 0 4 8 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 92 96 100 104 108 112 116 120 128 136 144 148 160 164 168 172 174 188 196 200 204 212 216 220 226 228 236 240 244 249 252 256 260 264 268 277 280 281 284 285 +TICK +CX 118 95 273 8 178 155 270 247 54 31 5 28 20 285 266 243 50 27 97 120 2 267 1 24 224 115 189 212 93 116 33 56 125 148 245 268 29 52 217 240 222 199 121 144 126 103 272 249 186 163 213 236 218 195 62 39 94 71 214 191 154 131 58 35 246 223 197 220 6 271 73 96 193 216 165 188 69 92 221 244 37 60 102 79 117 226 194 171 98 75 70 47 34 11 282 259 66 43 77 100 250 227 152 167 14 279 255 278 251 274 10 275 261 284 45 68 65 174 137 160 257 280 41 64 229 252 9 32 265 0 74 51 231 254 262 239 12 277 258 235 42 19 162 139 134 111 38 15 85 108 130 107 177 200 81 104 18 283 141 164 173 196 113 136 233 256 17 40 49 72 205 228 210 187 114 91 13 36 206 183 105 128 110 87 82 59 242 133 202 179 142 119 269 4 46 23 78 55 170 147 230 207 16 281 61 84 181 204 263 286 22 287 57 80 89 112 149 172 53 76 241 264 25 48 30 7 145 168 90 67 237 260 21 44 26 3 182 159 86 63 +TICK +CX 54 13 262 197 2 249 199 232 103 136 258 193 22 245 162 97 75 108 195 228 227 260 11 44 222 181 185 226 126 85 183 192 46 269 119 128 62 21 278 237 118 53 250 209 154 113 210 145 58 17 114 49 147 180 246 205 10 257 51 84 6 253 279 0 142 77 138 73 171 204 34 281 203 236 107 140 102 61 242 175 194 153 191 200 98 57 95 104 254 213 214 149 267 12 187 196 130 89 91 100 90 25 63 72 283 4 14 261 55 88 238 173 243 276 184 117 47 56 110 69 179 212 83 116 139 148 43 52 202 161 38 285 79 112 167 234 135 144 78 37 39 48 170 129 133 174 74 33 71 80 271 16 163 172 67 76 282 217 186 121 255 264 132 65 159 168 35 68 134 93 224 157 94 29 127 160 31 64 287 8 27 60 239 248 59 92 235 244 19 28 111 120 270 229 231 240 15 24 206 165 146 105 266 225 50 9 263 272 82 41 259 268 275 20 30 277 131 164 230 189 286 221 70 5 26 273 190 125 115 156 223 256 7 40 66 1 219 252 3 36 18 241 218 177 122 81 251 284 155 188 211 220 152 143 247 280 87 96 207 216 23 32 182 141 86 45 42 265 274 233 178 137 +TICK +CX 175 184 84 75 233 54 174 151 5 138 144 159 264 279 48 63 156 133 80 95 97 230 172 187 89 198 234 101 193 38 125 258 68 59 29 162 85 194 104 119 123 132 121 254 64 55 21 130 221 66 141 250 181 2 113 222 17 126 276 267 249 94 92 83 109 218 212 203 13 122 88 79 240 255 56 71 73 206 237 58 268 283 52 67 93 202 9 142 129 262 205 26 169 14 260 251 44 35 61 170 164 155 200 215 197 42 256 247 40 31 36 27 189 10 225 70 281 102 284 275 188 179 81 214 277 98 280 271 77 210 248 263 49 182 213 34 244 259 28 43 148 163 209 30 105 238 120 135 24 39 177 22 236 227 37 146 140 131 269 114 272 287 176 191 173 18 232 223 16 7 136 127 265 110 108 99 228 219 12 3 285 106 201 46 253 74 53 186 128 143 145 278 32 47 220 235 4 19 124 139 216 231 0 15 273 118 20 11 165 274 69 178 112 103 241 86 161 270 204 195 261 82 1 134 76 91 257 78 229 50 168 183 72 87 8 23 153 286 57 190 196 211 100 115 208 185 149 282 60 51 192 207 96 111 25 158 45 154 245 90 217 62 137 246 41 150 180 171 +TICK +CX 198 213 23 132 143 252 115 224 19 128 219 64 278 269 94 85 111 220 214 205 15 124 154 145 58 49 90 81 247 92 167 276 207 28 239 60 238 229 7 140 266 281 99 232 263 84 3 136 78 93 119 228 195 40 286 277 70 61 87 196 190 181 223 68 34 25 282 273 66 57 83 192 186 177 158 149 62 53 215 36 250 241 30 45 211 32 26 41 103 236 179 0 75 208 18 9 35 144 270 285 54 69 174 189 14 5 146 161 50 65 91 200 106 97 262 253 10 1 63 172 199 44 258 249 42 33 59 168 162 153 55 188 134 125 254 245 38 29 191 12 147 280 51 184 130 121 222 237 126 141 187 8 279 100 2 17 218 233 122 137 183 4 79 212 22 13 275 96 39 148 11 120 114 105 131 240 243 88 246 261 150 165 206 197 110 101 242 257 82 73 202 193 159 268 46 37 175 20 95 204 234 225 138 129 155 264 267 112 171 16 227 48 230 221 287 108 27 160 226 217 102 117 283 104 6 21 151 284 255 76 194 209 98 113 251 72 47 156 107 216 139 248 43 152 182 173 86 77 118 109 135 244 274 265 178 169 210 201 235 56 71 180 271 116 231 52 163 272 67 176 203 24 142 133 259 80 127 260 31 164 170 185 74 89 123 256 +TICK +CX 129 162 185 194 284 219 24 271 160 119 188 123 64 23 221 254 253 286 37 70 156 115 60 19 216 175 248 207 152 111 209 218 184 143 281 2 88 47 180 139 236 171 84 43 140 75 173 206 272 231 36 283 77 110 176 135 49 82 169 202 32 279 4 251 0 247 256 215 229 262 20 243 269 14 132 91 189 198 93 102 252 211 9 42 224 183 265 10 128 87 220 179 285 6 124 83 280 239 213 222 117 126 276 235 116 51 85 118 145 178 8 255 177 210 40 287 81 114 80 39 172 131 76 35 273 18 136 95 205 238 168 127 109 142 165 174 72 31 13 46 69 78 228 187 201 234 105 138 161 170 104 63 65 74 196 155 100 59 192 151 96 55 212 147 61 94 181 214 153 186 16 263 57 90 149 182 12 259 53 86 268 227 52 11 241 274 25 58 144 103 264 223 48 7 261 270 45 54 277 22 137 146 257 266 41 50 200 159 232 191 108 67 68 3 101 134 5 38 97 130 1 34 157 190 249 282 33 66 89 98 92 27 125 158 245 278 29 62 44 267 244 203 148 107 217 250 121 154 120 79 240 199 237 246 56 15 21 30 141 150 113 122 233 242 17 26 208 167 112 71 204 163 260 195 164 99 197 230 73 106 193 226 28 275 225 258 +TICK +CX 123 146 27 50 183 206 215 238 119 142 59 82 64 41 20 285 60 37 248 225 152 129 212 189 28 5 148 125 88 65 120 97 240 217 24 1 245 268 275 10 180 157 84 61 131 154 272 249 271 6 176 153 223 246 7 30 99 122 219 242 3 26 191 214 95 118 0 265 155 178 187 210 91 114 247 270 252 229 36 13 63 86 68 45 193 216 128 105 160 137 32 9 283 18 220 197 124 101 221 244 47 70 276 253 92 69 139 162 43 66 184 161 103 126 135 158 39 62 195 218 11 34 71 94 76 53 163 186 168 145 67 90 72 49 4 269 250 227 255 278 14 279 260 237 44 21 159 182 164 141 251 274 256 233 40 17 261 284 100 77 132 109 257 280 287 22 51 74 192 169 224 201 96 73 188 165 19 42 111 134 15 38 203 226 107 130 12 277 258 235 167 190 199 222 8 273 254 231 259 282 264 241 48 25 75 98 80 57 236 213 140 117 172 149 177 200 232 209 267 2 136 113 108 85 228 205 104 81 151 174 55 78 196 173 243 266 147 170 87 110 239 262 23 46 179 202 83 106 115 138 234 211 175 198 79 102 230 207 16 281 56 33 171 194 181 204 116 93 263 286 52 29 208 185 112 89 144 121 35 58 127 150 31 54 +TICK +MX 0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 160 164 168 172 176 177 180 181 184 188 192 193 196 208 212 220 221 224 228 232 236 240 245 248 252 256 257 260 261 264 272 276 +MZ 2 6 10 18 22 26 30 34 38 42 46 50 54 58 62 66 70 74 78 82 86 90 94 98 102 106 110 114 118 122 126 130 134 138 142 146 150 154 158 162 170 174 178 182 186 190 194 198 202 206 207 210 211 214 218 222 226 227 231 235 238 242 246 262 266 270 274 278 279 282 286 +TICK +RX 0 4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120 124 128 132 136 140 144 148 152 160 164 168 172 176 177 180 181 184 188 192 193 196 208 212 220 221 224 228 232 236 240 245 248 252 256 257 260 261 264 272 276 +R 2 6 10 18 22 26 30 34 38 42 46 50 54 58 62 66 70 74 78 82 86 90 94 98 102 106 110 114 118 122 126 130 134 138 142 146 150 154 158 162 170 174 178 182 186 190 194 198 202 206 207 210 211 214 218 222 226 227 231 235 238 242 246 262 266 270 274 278 279 282 286 +TICK +CX 123 146 27 50 183 206 215 238 119 142 59 82 64 41 20 285 60 37 248 225 152 129 212 189 28 5 148 125 88 65 120 97 240 217 24 1 245 268 275 10 180 157 84 61 131 154 272 249 271 6 176 153 223 246 7 30 99 122 219 242 3 26 191 214 95 118 0 265 155 178 187 210 91 114 247 270 252 229 36 13 63 86 68 45 193 216 128 105 160 137 32 9 283 18 220 197 124 101 221 244 47 70 276 253 92 69 139 162 43 66 184 161 103 126 135 158 39 62 195 218 11 34 71 94 76 53 163 186 168 145 67 90 72 49 4 269 250 227 255 278 14 279 260 237 44 21 159 182 164 141 251 274 256 233 40 17 261 284 100 77 132 109 257 280 287 22 51 74 192 169 224 201 96 73 188 165 19 42 111 134 15 38 203 226 107 130 12 277 258 235 167 190 199 222 8 273 254 231 259 282 264 241 48 25 75 98 80 57 236 213 140 117 172 149 177 200 232 209 267 2 136 113 108 85 228 205 104 81 151 174 55 78 196 173 243 266 147 170 87 110 239 262 23 46 179 202 83 106 115 138 234 211 175 198 79 102 230 207 16 281 56 33 171 194 181 204 116 93 263 286 52 29 208 185 112 89 144 121 35 58 127 150 31 54 +TICK +CX 129 162 185 194 284 219 24 271 160 119 188 123 64 23 221 254 253 286 37 70 156 115 60 19 216 175 248 207 152 111 209 218 184 143 281 2 88 47 180 139 236 171 84 43 140 75 173 206 272 231 36 283 77 110 176 135 49 82 169 202 32 279 4 251 0 247 256 215 229 262 20 243 269 14 132 91 189 198 93 102 252 211 9 42 224 183 265 10 128 87 220 179 285 6 124 83 280 239 213 222 117 126 276 235 116 51 85 118 145 178 8 255 177 210 40 287 81 114 80 39 172 131 76 35 273 18 136 95 205 238 168 127 109 142 165 174 72 31 13 46 69 78 228 187 201 234 105 138 161 170 104 63 65 74 196 155 100 59 192 151 96 55 212 147 61 94 181 214 153 186 16 263 57 90 149 182 12 259 53 86 268 227 52 11 241 274 25 58 144 103 264 223 48 7 261 270 45 54 277 22 137 146 257 266 41 50 200 159 232 191 108 67 68 3 101 134 5 38 97 130 1 34 157 190 249 282 33 66 89 98 92 27 125 158 245 278 29 62 44 267 244 203 148 107 217 250 121 154 120 79 240 199 237 246 56 15 21 30 141 150 113 122 233 242 17 26 208 167 112 71 204 163 260 195 164 99 197 230 73 106 193 226 28 275 225 258 +TICK +CX 198 213 23 132 143 252 115 224 19 128 219 64 278 269 94 85 111 220 214 205 15 124 154 145 58 49 90 81 247 92 167 276 207 28 239 60 238 229 7 140 266 281 99 232 263 84 3 136 78 93 119 228 195 40 286 277 70 61 87 196 190 181 223 68 34 25 282 273 66 57 83 192 186 177 158 149 62 53 215 36 250 241 30 45 211 32 26 41 103 236 179 0 75 208 18 9 35 144 270 285 54 69 174 189 14 5 146 161 50 65 91 200 106 97 262 253 10 1 63 172 199 44 258 249 42 33 59 168 162 153 55 188 134 125 254 245 38 29 191 12 147 280 51 184 130 121 222 237 126 141 187 8 279 100 2 17 218 233 122 137 183 4 79 212 22 13 275 96 39 148 11 120 114 105 131 240 243 88 246 261 150 165 206 197 110 101 242 257 82 73 202 193 159 268 46 37 175 20 95 204 234 225 138 129 155 264 267 112 171 16 227 48 230 221 287 108 27 160 226 217 102 117 283 104 6 21 151 284 255 76 194 209 98 113 251 72 47 156 107 216 139 248 43 152 182 173 86 77 118 109 135 244 274 265 178 169 210 201 235 56 71 180 271 116 231 52 163 272 67 176 203 24 142 133 259 80 127 260 31 164 170 185 74 89 123 256 +TICK +CX 141 182 277 30 140 107 113 154 272 263 233 274 17 58 176 167 232 199 273 26 136 103 205 246 109 150 108 75 101 124 228 195 197 262 0 279 152 129 189 230 93 134 265 42 185 226 32 23 221 286 220 211 181 222 143 128 153 194 16 271 57 98 216 207 213 254 117 158 209 250 249 2 112 79 281 34 204 171 236 203 173 238 76 67 49 114 169 234 168 159 72 63 4 283 69 110 161 202 65 106 37 78 157 198 20 275 269 46 60 27 33 74 192 183 224 215 96 87 285 38 253 6 116 83 149 214 53 118 208 175 25 90 145 210 8 287 264 255 48 39 80 71 172 163 41 82 229 270 68 35 9 50 225 266 241 18 5 70 104 95 160 127 64 31 97 162 261 14 196 187 1 66 156 123 257 10 92 59 212 179 29 94 184 151 88 55 133 142 217 282 121 186 177 218 81 122 180 147 56 47 268 259 52 43 144 135 13 54 45 86 206 73 245 22 44 11 201 242 260 227 164 131 105 146 137 178 200 191 256 223 40 7 115 138 193 258 132 99 252 219 36 3 284 251 188 155 280 247 89 130 248 239 276 243 125 190 12 267 85 126 28 19 244 235 148 139 120 111 240 231 24 15 237 278 21 62 +TICK +CX 79 88 33 100 135 120 250 141 39 24 267 276 154 45 210 77 171 180 106 285 246 137 287 272 71 56 10 189 46 201 102 281 163 148 283 268 67 52 6 185 255 240 159 144 98 277 35 44 234 101 138 5 127 136 31 40 34 213 90 245 123 132 27 36 86 241 198 89 124 115 275 284 59 68 194 85 235 220 19 4 271 280 111 96 214 81 231 216 15 0 130 21 167 152 182 49 78 257 139 206 259 244 74 253 238 105 131 140 223 232 7 16 99 108 202 93 219 228 3 12 62 217 94 249 155 164 247 256 26 205 190 57 207 192 239 224 23 8 226 117 282 149 186 53 158 25 278 145 50 229 82 261 263 248 103 112 178 69 195 204 227 236 11 20 70 225 270 161 174 65 146 37 66 221 129 170 266 157 215 200 119 104 258 125 142 51 251 260 162 29 128 61 30 209 211 196 134 1 254 121 286 153 87 72 126 17 18 173 218 109 122 13 54 233 14 169 203 212 107 116 150 41 199 208 42 197 242 133 274 165 75 84 38 193 191 176 95 80 143 184 187 172 91 76 230 97 279 264 63 48 2 181 183 168 118 273 22 177 151 160 58 237 55 64 114 269 243 252 147 156 110 265 222 113 47 32 179 188 83 92 43 28 +TICK +CX 268 201 279 58 134 67 144 77 94 3 264 197 200 133 232 165 108 41 114 47 270 203 56 277 174 107 267 70 146 79 266 199 52 273 82 15 44 241 283 62 244 177 138 71 30 251 148 81 120 53 230 163 286 195 240 173 26 247 190 99 208 141 218 151 112 45 122 55 54 275 64 285 204 137 90 23 61 170 86 19 28 249 178 111 284 193 24 245 160 93 188 97 156 89 216 149 2 223 248 181 152 85 115 100 22 219 88 21 180 113 236 145 84 17 140 49 222 155 126 59 272 205 36 257 282 215 176 109 51 184 186 119 46 243 158 91 32 253 278 211 118 27 4 225 250 183 154 87 0 221 246 179 10 231 256 189 150 83 20 217 6 227 252 185 224 157 96 29 220 153 34 255 280 213 66 287 106 39 124 139 276 209 116 25 198 131 102 35 162 95 194 127 98 31 8 229 254 187 40 261 214 123 80 13 130 63 172 105 271 50 18 239 136 69 168 101 228 161 14 235 238 147 110 43 42 263 192 125 202 135 38 259 92 1 169 260 48 269 212 121 78 11 74 7 16 237 226 159 12 233 258 191 68 265 +TICK +MX 2 6 10 14 18 22 26 30 34 38 42 46 54 66 74 78 82 86 90 94 98 102 106 110 114 118 122 124 126 130 134 138 146 150 154 158 162 174 178 186 190 194 198 202 214 218 222 226 230 238 246 250 254 258 266 267 270 271 278 279 282 283 286 +MZ 1 13 17 21 25 29 41 45 49 53 69 77 81 85 89 93 97 100 101 105 109 113 121 125 133 137 141 145 149 153 157 161 165 170 173 177 181 184 185 189 193 197 201 205 209 213 217 221 225 229 233 237 241 245 249 253 257 260 261 265 269 273 277 285 +TICK +RX 2 6 10 14 18 22 26 30 34 38 42 46 54 66 74 78 82 86 90 94 98 102 106 110 114 118 122 124 126 130 134 138 146 150 154 158 162 174 178 186 190 194 198 202 214 218 222 226 230 238 246 250 254 258 266 267 270 271 278 279 282 283 286 +R 1 13 17 21 25 29 41 45 49 53 69 77 81 85 89 93 97 100 101 105 109 113 121 125 133 137 141 145 149 153 157 161 165 170 173 177 181 184 185 189 193 197 201 205 209 213 217 221 225 229 233 237 241 245 249 253 257 260 261 265 269 273 277 285 +TICK +CX 268 201 279 58 134 67 144 77 94 3 264 197 200 133 232 165 108 41 114 47 270 203 56 277 174 107 267 70 146 79 266 199 52 273 82 15 44 241 283 62 244 177 138 71 30 251 148 81 120 53 230 163 286 195 240 173 26 247 190 99 208 141 218 151 112 45 122 55 54 275 64 285 204 137 90 23 61 170 86 19 28 249 178 111 284 193 24 245 160 93 188 97 156 89 216 149 2 223 248 181 152 85 115 100 22 219 88 21 180 113 236 145 84 17 140 49 222 155 126 59 272 205 36 257 282 215 176 109 51 184 186 119 46 243 158 91 32 253 278 211 118 27 4 225 250 183 154 87 0 221 246 179 10 231 256 189 150 83 20 217 6 227 252 185 224 157 96 29 220 153 34 255 280 213 66 287 106 39 124 139 276 209 116 25 198 131 102 35 162 95 194 127 98 31 8 229 254 187 40 261 214 123 80 13 130 63 172 105 271 50 18 239 136 69 168 101 228 161 14 235 238 147 110 43 42 263 192 125 202 135 38 259 92 1 169 260 48 269 212 121 78 11 74 7 16 237 226 159 12 233 258 191 68 265 +TICK +CX 79 88 33 100 135 120 250 141 39 24 267 276 154 45 210 77 171 180 106 285 246 137 287 272 71 56 10 189 46 201 102 281 163 148 283 268 67 52 6 185 255 240 159 144 98 277 35 44 234 101 138 5 127 136 31 40 34 213 90 245 123 132 27 36 86 241 198 89 124 115 275 284 59 68 194 85 235 220 19 4 271 280 111 96 214 81 231 216 15 0 130 21 167 152 182 49 78 257 139 206 259 244 74 253 238 105 131 140 223 232 7 16 99 108 202 93 219 228 3 12 62 217 94 249 155 164 247 256 26 205 190 57 207 192 239 224 23 8 226 117 282 149 186 53 158 25 278 145 50 229 82 261 263 248 103 112 178 69 195 204 227 236 11 20 70 225 270 161 174 65 146 37 66 221 129 170 266 157 215 200 119 104 258 125 142 51 251 260 162 29 128 61 30 209 211 196 134 1 254 121 286 153 87 72 126 17 18 173 218 109 122 13 54 233 14 169 203 212 107 116 150 41 199 208 42 197 242 133 274 165 75 84 38 193 191 176 95 80 143 184 187 172 91 76 230 97 279 264 63 48 2 181 183 168 118 273 22 177 151 160 58 237 55 64 114 269 243 252 147 156 110 265 222 113 47 32 179 188 83 92 43 28 +TICK +CX 141 182 277 30 140 107 113 154 272 263 233 274 17 58 176 167 232 199 273 26 136 103 205 246 109 150 108 75 101 124 228 195 197 262 0 279 152 129 189 230 93 134 265 42 185 226 32 23 221 286 220 211 181 222 143 128 153 194 16 271 57 98 216 207 213 254 117 158 209 250 249 2 112 79 281 34 204 171 236 203 173 238 76 67 49 114 169 234 168 159 72 63 4 283 69 110 161 202 65 106 37 78 157 198 20 275 269 46 60 27 33 74 192 183 224 215 96 87 285 38 253 6 116 83 149 214 53 118 208 175 25 90 145 210 8 287 264 255 48 39 80 71 172 163 41 82 229 270 68 35 9 50 225 266 241 18 5 70 104 95 160 127 64 31 97 162 261 14 196 187 1 66 156 123 257 10 92 59 212 179 29 94 184 151 88 55 133 142 217 282 121 186 177 218 81 122 180 147 56 47 268 259 52 43 144 135 13 54 45 86 206 73 245 22 44 11 201 242 260 227 164 131 105 146 137 178 200 191 256 223 40 7 115 138 193 258 132 99 252 219 36 3 284 251 188 155 280 247 89 130 248 239 276 243 125 190 12 267 85 126 28 19 244 235 148 139 120 111 240 231 24 15 237 278 21 62 +TICK diff --git a/visualisations/colour_hex_d3_d7_dropQ0_dropE0_L2_R1.stim b/visualisations/colour_square_deg4_d7_dropQ2_dropE0_L3_R1.stim similarity index 63% rename from visualisations/colour_hex_d3_d7_dropQ0_dropE0_L2_R1.stim rename to visualisations/colour_square_deg4_d7_dropQ2_dropE0_L3_R1.stim index ac8e59a..95b7176 100644 --- a/visualisations/colour_hex_d3_d7_dropQ0_dropE0_L2_R1.stim +++ b/visualisations/colour_square_deg4_d7_dropQ2_dropE0_L3_R1.stim @@ -7,6 +7,12 @@ ##! SHEET NAME=E Z=1 ##! SHEET NAME=UNTX Z=2 ##! SHEET NAME=UNTZ Z=3 +##! SHEET NAME=ANTIX Z=4 +##! SHEET NAME=ANTIZ Z=5 +##! SHEET NAME=PRODX Z=6 +##! SHEET NAME=PRODZ Z=7 +##! SHEET NAME=GAUGEX Z=8 +##! SHEET NAME=GAUGEZ Z=9 ##! QUBIT Q=0 SHEET=QUBITS X=1 Y=1 COLOUR=gold QUBIT_COORDS(1, 1) 0 ##! QUBIT Q=1 SHEET=QUBITS X=1 Y=2 COLOUR=gold @@ -45,7 +51,8 @@ QUBIT_COORDS(3, 5) 16 QUBIT_COORDS(4, 3) 17 ##! QUBIT Q=18 SHEET=QUBITS X=4 Y=2 COLOUR=gold QUBIT_COORDS(4, 2) 18 -##! QUBIT Q=19 SHEET=QUBITS X=4 Y=1 COLOUR=gold +##! HIGHLIGHT TARGET=QUBIT QUBITS=19 COLOR=red +##! QUBIT Q=19 SHEET=QUBITS X=4 Y=1 COLOUR=gold DEFECTIVE=true QUBIT_COORDS(4, 1) 19 ##! QUBIT Q=20 SHEET=QUBITS X=4 Y=5 COLOUR=gold QUBIT_COORDS(4, 5) 20 @@ -207,9 +214,10 @@ QUBIT_COORDS(6, 14) 97 QUBIT_COORDS(0, 0) 98 ##! QUBIT Q=99 SHEET=QUBITS X=1 Y=0 COLOUR=gold QUBIT_COORDS(1, 0) 99 -##! QUBIT Q=100 SHEET=QUBITS X=10 Y=0 COLOUR=gold +##! HIGHLIGHT TARGET=QUBIT QUBITS=100 COLOR=red +##! QUBIT Q=100 SHEET=QUBITS X=10 Y=0 COLOUR=gold DEFECTIVE=true QUBIT_COORDS(10, 0) 100 -##! CONN SET SHEET=E EDGES=(0-1,0-5,0-99,1-2,2-3,2-85,3-4,3-10,4-5,4-7,5-6,6-9,6-99,7-8,7-12,8-9,8-19,9-29,10-11,10-13,11-12,11-16,12-17,13-14,13-86,14-15,15-16,15-22,16-20,17-18,17-21,18-19,18-30,19-29,20-21,20-24,21-33,22-23,22-25,23-24,23-28,24-35,25-26,26-27,26-90,27-28,27-39,28-37,29-32,30-31,30-34,31-32,31-48,32-60,33-34,33-36,34-46,35-36,35-38,36-49,37-38,37-41,38-51,39-40,39-42,40-41,40-45,41-53,42-43,42-91,43-44,44-45,44-57,45-55,46-47,46-50,47-48,47-61,48-60,49-50,49-52,50-64,51-52,51-54,52-66,53-54,53-56,54-68,55-56,55-59,56-70,57-58,57-94,58-59,58-97,60-63,61-62,61-65,62-63,62-74,63-79,64-65,64-67,65-72,66-67,66-69,67-75,68-69,68-71,69-77,70-71,71-92,72-73,72-76,73-74,73-80,74-79,75-76,75-78,76-83,77-78,77-93,79-82,80-81,80-84,81-82,81-89,82-100,83-84,84-87,85-86,87-88,88-89,89-100,90-91,92-93,94-95,95-96,96-97,98-99) THICKNESS=2 COLOUR=#4361ee +##! CONN SET SHEET=E EDGES=(0-1,0-5,0-99,1-2,1-4,2-3,2-85,3-4,3-10,3-12,4-5,4-7,5-6,5-8,6-9,6-99,7-8,7-12,7-18,8-9,8-19,9-29,10-11,10-13,10-85,11-12,11-16,11-21,12-17,13-14,13-16,13-86,14-15,15-16,15-22,15-24,16-20,17-18,17-21,17-34,18-19,18-30,19-29,19-31,20-21,20-24,20-36,21-33,22-23,22-25,23-24,23-28,23-38,24-35,25-26,25-28,26-27,26-90,27-28,27-39,27-41,28-37,29-32,30-31,30-34,30-47,31-32,31-48,32-60,33-34,33-36,33-50,34-46,35-36,35-38,35-52,36-49,37-38,37-41,37-54,38-51,39-40,39-42,39-90,40-41,40-45,40-56,41-53,42-43,42-45,42-91,43-44,44-45,44-57,44-59,45-55,46-47,46-50,46-65,47-48,47-61,48-60,48-62,49-50,49-52,49-67,50-64,51-52,51-54,51-69,52-66,53-54,53-56,53-71,54-68,55-56,55-59,56-70,57-58,57-94,58-59,58-97,60-63,61-62,61-65,61-73,62-63,62-74,63-79,64-65,64-67,64-76,65-72,66-67,66-69,66-78,67-75,68-69,68-71,68-93,69-77,70-71,71-92,72-73,72-76,72-84,73-74,73-80,74-79,74-81,75-76,75-78,76-83,77-78,77-93,79-82,80-81,80-84,80-88,81-82,81-89,82-100,83-84,84-87,85-86,87-88,88-89,89-100,90-91,92-93,94-95,94-97,95-96,96-97,98-99) THICKNESS=2 COLOUR=#4361ee ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 1 2 3 4 5 0 ##! POLY SHEET=UNTX @@ -219,16 +227,12 @@ QUBIT_COORDS(10, 0) 100 ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 13 14 15 16 11 10 ##! POLY SHEET=UNTX -#!pragma POLYGON(1,0,0,0.15) 7 12 17 18 19 8 -##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 11 16 20 21 17 12 ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 15 22 23 24 20 16 ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 25 26 27 28 23 22 ##! POLY SHEET=UNTX -#!pragma POLYGON(1,0,0,0.15) 19 18 30 31 32 29 -##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 17 21 33 34 30 18 ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 20 24 35 36 33 21 @@ -303,13 +307,9 @@ QUBIT_COORDS(10, 0) 100 ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 0 5 6 99 ##! POLY SHEET=UNTX -#!pragma POLYGON(1,0,0,0.15) 8 19 29 9 -##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 31 48 60 32 ##! POLY SHEET=UNTX #!pragma POLYGON(1,0,0,0.15) 62 74 79 63 -##! POLY SHEET=UNTX -#!pragma POLYGON(1,0,0,0.15) 81 89 100 82 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 1 2 3 4 5 0 ##! POLY SHEET=UNTZ @@ -319,16 +319,12 @@ QUBIT_COORDS(10, 0) 100 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 13 14 15 16 11 10 ##! POLY SHEET=UNTZ -#!pragma POLYGON(0,0,1,0.15) 7 12 17 18 19 8 -##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 11 16 20 21 17 12 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 15 22 23 24 20 16 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 25 26 27 28 23 22 ##! POLY SHEET=UNTZ -#!pragma POLYGON(0,0,1,0.15) 19 18 30 31 32 29 -##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 17 21 33 34 30 18 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 20 24 35 36 33 21 @@ -403,46 +399,93 @@ QUBIT_COORDS(10, 0) 100 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 0 5 6 99 ##! POLY SHEET=UNTZ -#!pragma POLYGON(0,0,1,0.15) 8 19 29 9 -##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 31 48 60 32 ##! POLY SHEET=UNTZ #!pragma POLYGON(0,0,1,0.15) 62 74 79 63 -##! POLY SHEET=UNTZ -#!pragma POLYGON(0,0,1,0.15) 81 89 100 82 -CX 41 40 57 94 72 76 5 4 69 68 3 10 23 28 77 93 17 21 19 18 65 64 74 73 75 78 13 14 53 56 55 59 26 90 38 37 84 83 22 25 46 50 48 47 0 1 49 52 34 33 89 88 58 97 62 61 27 39 71 70 16 15 81 80 42 43 12 11 67 66 51 54 20 24 31 30 8 7 36 35 45 44 2 85 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 12 17 18 8 7 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 18 30 31 32 29 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 8 29 9 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 81 89 82 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 12 17 18 8 7 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 18 30 31 32 29 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 8 29 9 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 81 89 82 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 7 12 17 18 29 9 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 7 12 17 30 31 32 29 8 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 7 12 17 18 29 9 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 7 12 17 30 31 32 29 8 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 12 17 18 8 7 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 81 89 82 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 12 17 18 8 7 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 81 89 82 +##! HIGHLIGHT TARGET=QUBIT QUBITS=19,100 COLOR=red +CX 77 69 23 22 17 12 68 54 97 96 1 0 30 18 53 41 28 27 64 50 47 46 93 92 88 87 56 55 52 51 4 5 38 37 84 83 80 73 34 33 11 10 76 75 71 70 72 65 16 15 58 57 67 66 98 99 48 31 21 20 49 36 89 81 40 39 2 3 45 44 85 86 91 90 60 32 7 8 35 24 +TICK +CX 41 40 50 49 51 38 18 17 57 94 96 95 59 58 69 68 78 77 39 42 9 8 83 76 65 64 63 62 15 14 6 5 24 23 20 16 22 25 85 2 79 74 32 29 61 47 70 56 81 80 12 11 44 43 46 34 87 84 66 52 31 30 92 71 99 0 75 67 37 28 10 13 1 4 27 26 36 35 33 21 55 45 54 53 73 72 +TICK +CX 32 31 33 36 82 81 72 76 23 28 17 21 79 63 66 69 75 78 25 26 13 14 53 56 10 85 18 7 55 59 62 74 35 38 57 44 6 99 46 50 49 52 2 1 11 16 68 71 37 41 29 9 60 48 42 43 64 67 51 54 20 24 22 15 61 65 5 8 80 84 40 45 94 95 30 34 +TICK +MX 2 6 10 18 20 22 29 32 33 37 46 51 55 57 60 61 66 75 79 88 91 93 97 +MZ 0 8 14 16 21 26 28 31 34 38 43 45 52 56 67 71 74 76 81 84 86 87 90 92 95 96 +TICK +RX 2 6 10 18 20 22 29 32 33 37 46 51 55 57 60 61 66 75 79 88 91 93 97 +R 0 8 14 16 21 26 28 31 34 38 43 45 52 56 67 71 74 76 81 84 86 87 90 92 95 96 +TICK +CX 32 31 33 36 82 81 72 76 23 28 17 21 79 63 66 69 75 78 25 26 13 14 53 56 10 85 18 7 55 59 62 74 35 38 57 44 6 99 46 50 49 52 2 1 11 16 68 71 37 41 29 9 60 48 42 43 64 67 51 54 20 24 22 15 61 65 5 8 80 84 40 45 94 95 30 34 +TICK +CX 41 40 50 49 51 38 18 17 57 94 96 95 59 58 69 68 78 77 39 42 9 8 83 76 65 64 63 62 15 14 6 5 24 23 20 16 22 25 85 2 79 74 32 29 61 47 70 56 81 80 12 11 44 43 46 34 87 84 66 52 31 30 92 71 99 0 75 67 37 28 10 13 1 4 27 26 36 35 33 21 55 45 54 53 73 72 +TICK +CX 77 69 23 22 17 12 68 54 97 96 1 0 30 18 53 41 28 27 64 50 47 46 93 92 88 87 56 55 52 51 4 5 38 37 84 83 80 73 34 33 11 10 76 75 71 70 72 65 16 15 58 57 67 66 98 99 48 31 21 20 49 36 89 81 40 39 2 3 45 44 85 86 91 90 60 32 7 8 35 24 +TICK +CX 41 40 72 76 5 4 69 68 3 10 23 28 97 96 77 93 17 21 65 64 74 73 75 78 13 14 53 56 55 59 26 90 38 37 84 83 22 25 46 50 48 47 0 1 49 52 34 33 89 88 62 61 27 39 71 70 16 15 81 80 99 98 42 43 12 11 58 57 67 66 18 30 51 54 20 24 8 7 36 35 45 44 2 85 TICK -CX 32 31 50 49 90 91 18 17 33 36 82 81 4 3 59 58 78 77 44 57 39 42 9 8 97 96 100 89 63 62 66 69 25 26 28 27 47 46 93 92 6 5 24 23 88 87 56 55 29 19 52 51 35 38 1 2 11 16 76 75 68 71 37 41 79 74 60 48 7 12 15 22 64 67 21 20 61 65 80 84 99 0 40 45 10 13 85 86 54 53 94 95 73 72 30 34 +CX 50 49 90 91 96 95 33 36 12 7 3 4 82 81 57 94 78 77 29 32 8 9 39 42 63 62 17 18 66 69 28 27 47 46 93 92 24 23 88 87 56 55 0 99 52 51 35 38 5 6 2 1 11 16 76 75 68 71 59 44 37 41 79 74 60 48 15 22 64 67 21 20 61 65 80 84 40 45 10 13 85 86 54 53 30 31 73 72 25 26 TICK -CX 16 20 26 27 84 87 22 23 69 77 95 96 68 54 0 5 30 18 7 4 64 50 34 46 36 49 15 14 45 55 86 13 56 70 62 74 71 92 80 73 65 72 11 10 63 60 91 42 32 29 61 47 99 98 82 79 81 89 44 43 67 75 12 17 41 53 66 52 57 58 9 6 40 39 37 28 38 51 2 3 8 19 31 48 33 21 76 83 35 24 +CX 51 38 26 27 22 23 31 32 44 57 69 77 68 54 53 41 64 50 9 29 15 14 45 55 12 3 56 70 20 16 62 74 80 73 8 5 11 10 63 60 72 65 61 47 13 86 82 79 81 89 7 18 67 75 87 84 49 36 34 17 66 52 92 71 40 39 37 28 99 6 1 4 33 21 94 95 76 83 42 91 35 24 TICK -MX 7 9 11 15 30 32 33 35 37 40 44 56 61 63 64 66 68 76 80 82 85 88 90 93 97 99 -MZ 3 5 13 17 19 20 23 27 42 46 48 49 51 53 55 58 72 74 75 77 87 89 92 96 +MX 0 8 11 12 15 33 34 35 37 40 56 61 63 64 66 68 76 80 82 85 88 90 93 97 +MZ 4 6 16 18 23 27 29 32 36 38 41 55 57 65 71 74 75 77 84 86 89 91 95 96 TICK -RX 7 9 11 15 30 32 33 35 37 40 44 56 61 63 64 66 68 76 80 82 85 88 90 93 97 99 -R 3 5 13 17 19 20 23 27 42 46 48 49 51 53 55 58 72 74 75 77 87 89 92 96 +RX 0 8 11 12 15 33 34 35 37 40 56 61 63 64 66 68 76 80 82 85 88 90 93 97 +R 4 6 16 18 23 27 29 32 36 38 41 55 57 65 71 74 75 77 84 86 89 91 95 96 TICK -CX 16 20 26 27 84 87 22 23 69 77 95 96 68 54 0 5 30 18 7 4 64 50 34 46 36 49 15 14 45 55 86 13 56 70 62 74 71 92 80 73 65 72 11 10 63 60 91 42 32 29 61 47 99 98 82 79 81 89 44 43 67 75 12 17 41 53 66 52 57 58 9 6 40 39 37 28 38 51 2 3 8 19 31 48 33 21 76 83 35 24 +CX 51 38 26 27 22 23 31 32 44 57 69 77 68 54 53 41 64 50 9 29 15 14 45 55 12 3 56 70 20 16 62 74 80 73 8 5 11 10 63 60 72 65 61 47 13 86 82 79 81 89 7 18 67 75 87 84 49 36 34 17 66 52 92 71 40 39 37 28 99 6 1 4 33 21 94 95 76 83 42 91 35 24 TICK -CX 32 31 50 49 90 91 18 17 33 36 82 81 4 3 59 58 78 77 44 57 39 42 9 8 97 96 100 89 63 62 66 69 25 26 28 27 47 46 93 92 6 5 24 23 88 87 56 55 29 19 52 51 35 38 1 2 11 16 76 75 68 71 37 41 79 74 60 48 7 12 15 22 64 67 21 20 61 65 80 84 99 0 40 45 10 13 85 86 54 53 94 95 73 72 30 34 +CX 50 49 90 91 96 95 33 36 12 7 3 4 82 81 57 94 78 77 29 32 8 9 39 42 63 62 17 18 66 69 28 27 47 46 93 92 24 23 88 87 56 55 0 99 52 51 35 38 5 6 2 1 11 16 76 75 68 71 59 44 37 41 79 74 60 48 15 22 64 67 21 20 61 65 80 84 40 45 10 13 85 86 54 53 30 31 73 72 25 26 TICK -CX 41 40 57 94 72 76 5 4 69 68 3 10 23 28 77 93 17 21 19 18 65 64 74 73 75 78 13 14 53 56 55 59 26 90 38 37 84 83 22 25 46 50 48 47 0 1 49 52 34 33 89 88 58 97 62 61 27 39 71 70 16 15 81 80 42 43 12 11 67 66 51 54 20 24 31 30 8 7 36 35 45 44 2 85 +CX 41 40 72 76 5 4 69 68 3 10 23 28 97 96 77 93 17 21 65 64 74 73 75 78 13 14 53 56 55 59 26 90 38 37 84 83 22 25 46 50 48 47 0 1 49 52 34 33 89 88 62 61 27 39 71 70 16 15 81 80 99 98 42 43 12 11 58 57 67 66 18 30 51 54 20 24 8 7 36 35 45 44 2 85 TICK -CX 50 46 59 55 52 49 39 27 35 36 44 45 56 53 14 13 93 77 40 41 10 3 1 0 68 69 64 65 25 22 24 20 90 26 18 19 73 74 43 42 4 5 94 57 85 2 28 23 83 84 76 72 37 38 54 51 97 58 15 16 88 89 47 48 33 34 21 17 78 75 61 62 70 71 80 81 11 12 66 67 30 31 7 8 +CX 50 46 59 55 52 49 39 27 35 36 44 45 56 53 14 13 93 77 40 41 10 3 1 0 68 69 64 65 25 22 24 20 96 97 90 26 73 74 43 42 4 5 28 23 83 84 76 72 37 38 54 51 15 16 88 89 47 48 33 34 98 99 21 17 78 75 61 62 70 71 57 58 80 81 11 12 66 67 30 31 7 8 TICK -CX 72 73 42 39 81 82 12 7 3 4 58 59 38 35 31 32 77 78 8 9 65 61 49 50 74 79 17 18 45 40 27 28 48 60 71 68 55 56 96 97 0 99 67 64 84 80 5 6 51 52 57 44 46 47 23 24 87 88 34 30 2 1 36 33 92 93 13 10 89 100 19 29 26 25 20 21 62 63 69 66 22 15 86 85 95 94 75 76 91 90 53 54 41 37 16 11 +CX 32 31 72 73 42 39 81 82 12 7 3 4 38 35 77 78 95 96 65 61 9 8 49 50 74 79 17 18 45 40 27 28 71 68 6 5 55 56 67 64 84 80 94 57 51 52 46 47 23 24 87 88 34 30 2 1 36 33 92 93 13 10 60 48 26 25 43 44 20 21 69 66 22 15 99 0 75 76 91 90 53 54 63 62 41 37 16 11 TICK -CX 96 95 51 38 77 69 84 87 50 64 23 22 17 12 29 32 83 76 53 41 24 35 20 16 47 61 73 80 42 91 5 0 21 33 52 66 14 15 19 8 10 11 79 82 72 65 70 56 13 86 3 2 58 57 98 99 4 7 46 34 18 30 60 63 43 44 49 36 92 71 48 31 89 81 74 62 39 40 75 67 27 26 28 37 55 45 6 9 54 68 +CX 16 20 77 69 84 87 50 64 23 22 44 57 83 76 34 46 36 49 24 35 47 61 73 80 71 92 21 33 52 66 14 15 6 99 10 11 65 72 48 62 91 42 29 9 70 56 4 7 18 30 12 17 41 53 95 94 5 8 89 81 39 40 75 67 38 51 2 3 27 26 85 86 60 32 28 37 55 45 79 82 54 68 TICK -MX 3 5 13 17 19 20 23 27 42 46 48 49 51 53 55 58 72 74 75 77 84 89 92 96 -MZ 7 9 11 15 30 32 33 35 37 40 44 56 61 63 64 66 68 76 80 82 85 88 90 93 97 99 +MX 2 6 12 16 23 27 29 34 36 38 41 55 60 65 71 75 77 84 85 89 91 95 96 +MZ 0 7 8 11 15 30 33 35 37 40 56 57 61 62 64 66 68 76 80 82 86 88 90 93 97 TICK -RX 3 5 13 17 19 20 23 27 42 46 48 49 51 53 55 58 72 74 75 77 84 89 92 96 -R 7 9 11 15 30 32 33 35 37 40 44 56 61 63 64 66 68 76 80 82 85 88 90 93 97 99 +RX 2 6 12 16 23 27 29 34 36 38 41 55 60 65 71 75 77 84 85 89 91 95 96 +R 0 7 8 11 15 30 33 35 37 40 56 57 61 62 64 66 68 76 80 82 86 88 90 93 97 TICK -CX 96 95 51 38 77 69 84 87 50 64 23 22 17 12 29 32 83 76 53 41 24 35 20 16 47 61 73 80 42 91 5 0 21 33 52 66 14 15 19 8 10 11 79 82 72 65 70 56 13 86 3 2 58 57 98 99 4 7 46 34 18 30 60 63 43 44 49 36 92 71 48 31 89 81 74 62 39 40 75 67 27 26 28 37 55 45 6 9 54 68 +CX 16 20 77 69 84 87 50 64 23 22 44 57 83 76 34 46 36 49 24 35 47 61 73 80 71 92 21 33 52 66 14 15 6 99 10 11 65 72 48 62 91 42 29 9 70 56 4 7 18 30 12 17 41 53 95 94 5 8 89 81 39 40 75 67 38 51 2 3 27 26 85 86 60 32 28 37 55 45 79 82 54 68 TICK -CX 72 73 42 39 81 82 12 7 3 4 58 59 38 35 31 32 77 78 8 9 65 61 49 50 74 79 17 18 45 40 27 28 48 60 71 68 55 56 96 97 0 99 67 64 84 80 5 6 51 52 57 44 46 47 23 24 87 88 34 30 2 1 36 33 92 93 13 10 89 100 19 29 26 25 20 21 62 63 69 66 22 15 86 85 95 94 75 76 91 90 53 54 41 37 16 11 +CX 32 31 72 73 42 39 81 82 12 7 3 4 38 35 77 78 95 96 65 61 9 8 49 50 74 79 17 18 45 40 27 28 71 68 6 5 55 56 67 64 84 80 94 57 51 52 46 47 23 24 87 88 34 30 2 1 36 33 92 93 13 10 60 48 26 25 43 44 20 21 69 66 22 15 99 0 75 76 91 90 53 54 63 62 41 37 16 11 TICK -CX 50 46 59 55 52 49 39 27 35 36 44 45 56 53 14 13 93 77 40 41 10 3 1 0 68 69 64 65 25 22 24 20 90 26 18 19 73 74 43 42 4 5 94 57 85 2 28 23 83 84 76 72 37 38 54 51 97 58 15 16 88 89 47 48 33 34 21 17 78 75 61 62 70 71 80 81 11 12 66 67 30 31 7 8 +CX 50 46 59 55 52 49 39 27 35 36 44 45 56 53 14 13 93 77 40 41 10 3 1 0 68 69 64 65 25 22 24 20 96 97 90 26 73 74 43 42 4 5 28 23 83 84 76 72 37 38 54 51 15 16 88 89 47 48 33 34 98 99 21 17 78 75 61 62 70 71 57 58 80 81 11 12 66 67 30 31 7 8 TICK diff --git a/visualisations/colour_square_deg4_d7_dropQ2_dropE4_L3_R1.stim b/visualisations/colour_square_deg4_d7_dropQ2_dropE4_L3_R1.stim new file mode 100644 index 0000000..ab583a2 --- /dev/null +++ b/visualisations/colour_square_deg4_d7_dropQ2_dropE4_L3_R1.stim @@ -0,0 +1,516 @@ +# Legend +# Qubits: L (c=0) = gold, R (c=1) = mediumseagreen +# Connections by class (name: colour): +# - E: #4361ee +##! EMBEDDING TYPE=PLANE LX=11 LY=16 +##! SHEET NAME=QUBITS Z=0 +##! SHEET NAME=E Z=1 +##! SHEET NAME=UNTX Z=2 +##! SHEET NAME=UNTZ Z=3 +##! SHEET NAME=ANTIX Z=4 +##! SHEET NAME=ANTIZ Z=5 +##! SHEET NAME=PRODX Z=6 +##! SHEET NAME=PRODZ Z=7 +##! SHEET NAME=GAUGEX Z=8 +##! SHEET NAME=GAUGEZ Z=9 +##! QUBIT Q=0 SHEET=QUBITS X=1 Y=1 COLOUR=gold +QUBIT_COORDS(1, 1) 0 +##! QUBIT Q=1 SHEET=QUBITS X=1 Y=2 COLOUR=gold +QUBIT_COORDS(1, 2) 1 +##! QUBIT Q=2 SHEET=QUBITS X=1 Y=3 COLOUR=gold +QUBIT_COORDS(1, 3) 2 +##! QUBIT Q=3 SHEET=QUBITS X=2 Y=3 COLOUR=gold +QUBIT_COORDS(2, 3) 3 +##! QUBIT Q=4 SHEET=QUBITS X=2 Y=2 COLOUR=gold +QUBIT_COORDS(2, 2) 4 +##! QUBIT Q=5 SHEET=QUBITS X=2 Y=1 COLOUR=gold +QUBIT_COORDS(2, 1) 5 +##! QUBIT Q=6 SHEET=QUBITS X=2 Y=0 COLOUR=gold +QUBIT_COORDS(2, 0) 6 +##! QUBIT Q=7 SHEET=QUBITS X=3 Y=2 COLOUR=gold +QUBIT_COORDS(3, 2) 7 +##! QUBIT Q=8 SHEET=QUBITS X=3 Y=1 COLOUR=gold +QUBIT_COORDS(3, 1) 8 +##! QUBIT Q=9 SHEET=QUBITS X=3 Y=0 COLOUR=gold +QUBIT_COORDS(3, 0) 9 +##! QUBIT Q=10 SHEET=QUBITS X=2 Y=4 COLOUR=gold +QUBIT_COORDS(2, 4) 10 +##! QUBIT Q=11 SHEET=QUBITS X=3 Y=4 COLOUR=gold +QUBIT_COORDS(3, 4) 11 +##! QUBIT Q=12 SHEET=QUBITS X=3 Y=3 COLOUR=gold +QUBIT_COORDS(3, 3) 12 +##! QUBIT Q=13 SHEET=QUBITS X=2 Y=5 COLOUR=gold +QUBIT_COORDS(2, 5) 13 +##! QUBIT Q=14 SHEET=QUBITS X=2 Y=6 COLOUR=gold +QUBIT_COORDS(2, 6) 14 +##! QUBIT Q=15 SHEET=QUBITS X=3 Y=6 COLOUR=gold +QUBIT_COORDS(3, 6) 15 +##! QUBIT Q=16 SHEET=QUBITS X=3 Y=5 COLOUR=gold +QUBIT_COORDS(3, 5) 16 +##! QUBIT Q=17 SHEET=QUBITS X=4 Y=3 COLOUR=gold +QUBIT_COORDS(4, 3) 17 +##! QUBIT Q=18 SHEET=QUBITS X=4 Y=2 COLOUR=gold +QUBIT_COORDS(4, 2) 18 +##! QUBIT Q=19 SHEET=QUBITS X=4 Y=1 COLOUR=gold +QUBIT_COORDS(4, 1) 19 +##! QUBIT Q=20 SHEET=QUBITS X=4 Y=5 COLOUR=gold +QUBIT_COORDS(4, 5) 20 +##! QUBIT Q=21 SHEET=QUBITS X=4 Y=4 COLOUR=gold +QUBIT_COORDS(4, 4) 21 +##! QUBIT Q=22 SHEET=QUBITS X=3 Y=7 COLOUR=gold +QUBIT_COORDS(3, 7) 22 +##! QUBIT Q=23 SHEET=QUBITS X=4 Y=7 COLOUR=gold +QUBIT_COORDS(4, 7) 23 +##! QUBIT Q=24 SHEET=QUBITS X=4 Y=6 COLOUR=gold +QUBIT_COORDS(4, 6) 24 +##! QUBIT Q=25 SHEET=QUBITS X=3 Y=8 COLOUR=gold +QUBIT_COORDS(3, 8) 25 +##! HIGHLIGHT TARGET=QUBIT QUBITS=26 COLOR=red +##! QUBIT Q=26 SHEET=QUBITS X=3 Y=9 COLOUR=gold DEFECTIVE=true +QUBIT_COORDS(3, 9) 26 +##! QUBIT Q=27 SHEET=QUBITS X=4 Y=9 COLOUR=gold +QUBIT_COORDS(4, 9) 27 +##! QUBIT Q=28 SHEET=QUBITS X=4 Y=8 COLOUR=gold +QUBIT_COORDS(4, 8) 28 +##! QUBIT Q=29 SHEET=QUBITS X=4 Y=0 COLOUR=gold +QUBIT_COORDS(4, 0) 29 +##! QUBIT Q=30 SHEET=QUBITS X=5 Y=2 COLOUR=gold +QUBIT_COORDS(5, 2) 30 +##! QUBIT Q=31 SHEET=QUBITS X=5 Y=1 COLOUR=gold +QUBIT_COORDS(5, 1) 31 +##! QUBIT Q=32 SHEET=QUBITS X=5 Y=0 COLOUR=gold +QUBIT_COORDS(5, 0) 32 +##! QUBIT Q=33 SHEET=QUBITS X=5 Y=4 COLOUR=gold +QUBIT_COORDS(5, 4) 33 +##! QUBIT Q=34 SHEET=QUBITS X=5 Y=3 COLOUR=gold +QUBIT_COORDS(5, 3) 34 +##! QUBIT Q=35 SHEET=QUBITS X=5 Y=6 COLOUR=gold +QUBIT_COORDS(5, 6) 35 +##! QUBIT Q=36 SHEET=QUBITS X=5 Y=5 COLOUR=gold +QUBIT_COORDS(5, 5) 36 +##! QUBIT Q=37 SHEET=QUBITS X=5 Y=8 COLOUR=gold +QUBIT_COORDS(5, 8) 37 +##! QUBIT Q=38 SHEET=QUBITS X=5 Y=7 COLOUR=gold +QUBIT_COORDS(5, 7) 38 +##! QUBIT Q=39 SHEET=QUBITS X=4 Y=10 COLOUR=gold +QUBIT_COORDS(4, 10) 39 +##! QUBIT Q=40 SHEET=QUBITS X=5 Y=10 COLOUR=gold +QUBIT_COORDS(5, 10) 40 +##! QUBIT Q=41 SHEET=QUBITS X=5 Y=9 COLOUR=gold +QUBIT_COORDS(5, 9) 41 +##! QUBIT Q=42 SHEET=QUBITS X=4 Y=11 COLOUR=gold +QUBIT_COORDS(4, 11) 42 +##! QUBIT Q=43 SHEET=QUBITS X=4 Y=12 COLOUR=gold +QUBIT_COORDS(4, 12) 43 +##! QUBIT Q=44 SHEET=QUBITS X=5 Y=12 COLOUR=gold +QUBIT_COORDS(5, 12) 44 +##! QUBIT Q=45 SHEET=QUBITS X=5 Y=11 COLOUR=gold +QUBIT_COORDS(5, 11) 45 +##! QUBIT Q=46 SHEET=QUBITS X=6 Y=3 COLOUR=gold +QUBIT_COORDS(6, 3) 46 +##! QUBIT Q=47 SHEET=QUBITS X=6 Y=2 COLOUR=gold +QUBIT_COORDS(6, 2) 47 +##! QUBIT Q=48 SHEET=QUBITS X=6 Y=1 COLOUR=gold +QUBIT_COORDS(6, 1) 48 +##! QUBIT Q=49 SHEET=QUBITS X=6 Y=5 COLOUR=gold +QUBIT_COORDS(6, 5) 49 +##! QUBIT Q=50 SHEET=QUBITS X=6 Y=4 COLOUR=gold +QUBIT_COORDS(6, 4) 50 +##! QUBIT Q=51 SHEET=QUBITS X=6 Y=7 COLOUR=gold +QUBIT_COORDS(6, 7) 51 +##! QUBIT Q=52 SHEET=QUBITS X=6 Y=6 COLOUR=gold +QUBIT_COORDS(6, 6) 52 +##! QUBIT Q=53 SHEET=QUBITS X=6 Y=9 COLOUR=gold +QUBIT_COORDS(6, 9) 53 +##! QUBIT Q=54 SHEET=QUBITS X=6 Y=8 COLOUR=gold +QUBIT_COORDS(6, 8) 54 +##! QUBIT Q=55 SHEET=QUBITS X=6 Y=11 COLOUR=gold +QUBIT_COORDS(6, 11) 55 +##! QUBIT Q=56 SHEET=QUBITS X=6 Y=10 COLOUR=gold +QUBIT_COORDS(6, 10) 56 +##! QUBIT Q=57 SHEET=QUBITS X=5 Y=13 COLOUR=gold +QUBIT_COORDS(5, 13) 57 +##! QUBIT Q=58 SHEET=QUBITS X=6 Y=13 COLOUR=gold +QUBIT_COORDS(6, 13) 58 +##! QUBIT Q=59 SHEET=QUBITS X=6 Y=12 COLOUR=gold +QUBIT_COORDS(6, 12) 59 +##! QUBIT Q=60 SHEET=QUBITS X=6 Y=0 COLOUR=gold +QUBIT_COORDS(6, 0) 60 +##! QUBIT Q=61 SHEET=QUBITS X=7 Y=2 COLOUR=gold +QUBIT_COORDS(7, 2) 61 +##! QUBIT Q=62 SHEET=QUBITS X=7 Y=1 COLOUR=gold +QUBIT_COORDS(7, 1) 62 +##! QUBIT Q=63 SHEET=QUBITS X=7 Y=0 COLOUR=gold +QUBIT_COORDS(7, 0) 63 +##! QUBIT Q=64 SHEET=QUBITS X=7 Y=4 COLOUR=gold +QUBIT_COORDS(7, 4) 64 +##! QUBIT Q=65 SHEET=QUBITS X=7 Y=3 COLOUR=gold +QUBIT_COORDS(7, 3) 65 +##! QUBIT Q=66 SHEET=QUBITS X=7 Y=6 COLOUR=gold +QUBIT_COORDS(7, 6) 66 +##! QUBIT Q=67 SHEET=QUBITS X=7 Y=5 COLOUR=gold +QUBIT_COORDS(7, 5) 67 +##! QUBIT Q=68 SHEET=QUBITS X=7 Y=8 COLOUR=gold +QUBIT_COORDS(7, 8) 68 +##! QUBIT Q=69 SHEET=QUBITS X=7 Y=7 COLOUR=gold +QUBIT_COORDS(7, 7) 69 +##! QUBIT Q=70 SHEET=QUBITS X=7 Y=10 COLOUR=gold +QUBIT_COORDS(7, 10) 70 +##! QUBIT Q=71 SHEET=QUBITS X=7 Y=9 COLOUR=gold +QUBIT_COORDS(7, 9) 71 +##! QUBIT Q=72 SHEET=QUBITS X=8 Y=3 COLOUR=gold +QUBIT_COORDS(8, 3) 72 +##! QUBIT Q=73 SHEET=QUBITS X=8 Y=2 COLOUR=gold +QUBIT_COORDS(8, 2) 73 +##! QUBIT Q=74 SHEET=QUBITS X=8 Y=1 COLOUR=gold +QUBIT_COORDS(8, 1) 74 +##! QUBIT Q=75 SHEET=QUBITS X=8 Y=5 COLOUR=gold +QUBIT_COORDS(8, 5) 75 +##! QUBIT Q=76 SHEET=QUBITS X=8 Y=4 COLOUR=gold +QUBIT_COORDS(8, 4) 76 +##! QUBIT Q=77 SHEET=QUBITS X=8 Y=7 COLOUR=gold +QUBIT_COORDS(8, 7) 77 +##! QUBIT Q=78 SHEET=QUBITS X=8 Y=6 COLOUR=gold +QUBIT_COORDS(8, 6) 78 +##! QUBIT Q=79 SHEET=QUBITS X=8 Y=0 COLOUR=gold +QUBIT_COORDS(8, 0) 79 +##! QUBIT Q=80 SHEET=QUBITS X=9 Y=2 COLOUR=gold +QUBIT_COORDS(9, 2) 80 +##! QUBIT Q=81 SHEET=QUBITS X=9 Y=1 COLOUR=gold +QUBIT_COORDS(9, 1) 81 +##! QUBIT Q=82 SHEET=QUBITS X=9 Y=0 COLOUR=gold +QUBIT_COORDS(9, 0) 82 +##! QUBIT Q=83 SHEET=QUBITS X=9 Y=4 COLOUR=gold +QUBIT_COORDS(9, 4) 83 +##! QUBIT Q=84 SHEET=QUBITS X=9 Y=3 COLOUR=gold +QUBIT_COORDS(9, 3) 84 +##! QUBIT Q=85 SHEET=QUBITS X=1 Y=4 COLOUR=gold +QUBIT_COORDS(1, 4) 85 +##! QUBIT Q=86 SHEET=QUBITS X=1 Y=5 COLOUR=gold +QUBIT_COORDS(1, 5) 86 +##! QUBIT Q=87 SHEET=QUBITS X=10 Y=3 COLOUR=gold +QUBIT_COORDS(10, 3) 87 +##! QUBIT Q=88 SHEET=QUBITS X=10 Y=2 COLOUR=gold +QUBIT_COORDS(10, 2) 88 +##! QUBIT Q=89 SHEET=QUBITS X=10 Y=1 COLOUR=gold +QUBIT_COORDS(10, 1) 89 +##! QUBIT Q=90 SHEET=QUBITS X=3 Y=10 COLOUR=gold +QUBIT_COORDS(3, 10) 90 +##! QUBIT Q=91 SHEET=QUBITS X=3 Y=11 COLOUR=gold +QUBIT_COORDS(3, 11) 91 +##! QUBIT Q=92 SHEET=QUBITS X=8 Y=9 COLOUR=gold +QUBIT_COORDS(8, 9) 92 +##! QUBIT Q=93 SHEET=QUBITS X=8 Y=8 COLOUR=gold +QUBIT_COORDS(8, 8) 93 +##! QUBIT Q=94 SHEET=QUBITS X=5 Y=14 COLOUR=gold +QUBIT_COORDS(5, 14) 94 +##! HIGHLIGHT TARGET=QUBIT QUBITS=95 COLOR=red +##! QUBIT Q=95 SHEET=QUBITS X=5 Y=15 COLOUR=gold DEFECTIVE=true +QUBIT_COORDS(5, 15) 95 +##! QUBIT Q=96 SHEET=QUBITS X=6 Y=15 COLOUR=gold +QUBIT_COORDS(6, 15) 96 +##! QUBIT Q=97 SHEET=QUBITS X=6 Y=14 COLOUR=gold +QUBIT_COORDS(6, 14) 97 +##! QUBIT Q=98 SHEET=QUBITS X=0 Y=0 COLOUR=gold +QUBIT_COORDS(0, 0) 98 +##! QUBIT Q=99 SHEET=QUBITS X=1 Y=0 COLOUR=gold +QUBIT_COORDS(1, 0) 99 +##! QUBIT Q=100 SHEET=QUBITS X=10 Y=0 COLOUR=gold +QUBIT_COORDS(10, 0) 100 +##! CONN SET SHEET=E EDGES=(0-1,1-2,1-4,2-3,2-85,3-4,3-10,3-12,4-5,4-7,5-6,5-8,6-9,6-99,7-8,7-12,7-18,8-9,8-19,9-29,10-11,10-13,10-85,11-12,11-16,11-21,12-17,13-14,13-16,13-86,14-15,15-16,15-22,15-24,16-20,17-18,17-21,17-34,18-19,18-30,19-29,19-31,20-21,20-24,20-36,21-33,22-23,22-25,23-24,23-28,23-38,24-35,25-26,25-28,26-27,26-90,27-28,27-39,27-41,28-37,29-32,30-31,30-34,30-47,31-32,31-48,32-60,33-34,33-36,33-50,34-46,35-36,35-38,35-52,37-38,37-41,37-54,38-51,39-40,39-42,39-90,40-41,40-45,40-56,41-53,42-43,42-45,42-91,43-44,44-45,44-57,44-59,45-55,46-47,46-50,46-65,47-48,47-61,48-60,48-62,49-50,49-52,49-67,50-64,51-52,51-54,51-69,52-66,53-54,53-56,53-71,54-68,55-56,55-59,56-70,57-58,57-94,58-59,58-97,60-63,61-62,61-65,61-73,62-63,62-74,63-79,64-65,64-67,64-76,65-72,66-67,66-69,66-78,67-75,68-69,68-71,68-93,69-77,70-71,71-92,72-73,72-76,72-84,73-74,73-80,74-79,74-81,75-76,75-78,76-83,77-78,77-93,79-82,80-81,80-84,80-88,81-82,81-89,82-100,83-84,84-87,85-86,87-88,88-89,89-100,90-91,92-93,94-95,95-96,96-97,98-99) THICKNESS=2 COLOUR=#4361ee +##! CONN SET SHEET=E EDGES=(94-97,0-5,0-99,36-49) THICKNESS=2 COLOUR=red +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 5 4 7 8 9 6 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 3 10 11 12 7 4 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 13 14 15 16 11 10 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 7 12 17 18 19 8 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 11 16 20 21 17 12 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 15 22 23 24 20 16 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 19 18 30 31 32 29 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 17 21 33 34 30 18 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 20 24 35 36 33 21 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 23 28 37 38 35 24 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 27 39 40 41 37 28 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 42 43 44 45 40 39 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 30 34 46 47 48 31 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 33 36 49 50 46 34 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 35 38 51 52 49 36 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 37 41 53 54 51 38 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 40 45 55 56 53 41 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 44 57 58 59 55 45 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 48 47 61 62 63 60 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 46 50 64 65 61 47 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 49 52 66 67 64 50 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 51 54 68 69 66 52 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 53 56 70 71 68 54 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 61 65 72 73 74 62 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 64 67 75 76 72 65 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 66 69 77 78 75 67 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 74 73 80 81 82 79 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 72 76 83 84 80 73 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 85 86 13 10 3 2 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 80 84 87 88 89 81 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 68 71 92 93 77 69 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 25 22 15 14 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 94 57 44 43 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 75 78 83 76 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 55 59 70 56 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 85 86 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 90 91 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 87 88 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 92 93 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 96 97 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 8 19 29 9 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 31 48 60 32 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 62 74 79 63 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 81 89 100 82 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 5 4 7 8 9 6 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 3 10 11 12 7 4 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 13 14 15 16 11 10 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 7 12 17 18 19 8 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 11 16 20 21 17 12 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 15 22 23 24 20 16 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 19 18 30 31 32 29 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 17 21 33 34 30 18 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 20 24 35 36 33 21 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 23 28 37 38 35 24 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 27 39 40 41 37 28 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 42 43 44 45 40 39 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 30 34 46 47 48 31 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 33 36 49 50 46 34 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 35 38 51 52 49 36 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 37 41 53 54 51 38 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 40 45 55 56 53 41 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 44 57 58 59 55 45 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 48 47 61 62 63 60 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 46 50 64 65 61 47 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 49 52 66 67 64 50 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 51 54 68 69 66 52 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 53 56 70 71 68 54 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 61 65 72 73 74 62 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 64 67 75 76 72 65 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 66 69 77 78 75 67 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 74 73 80 81 82 79 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 72 76 83 84 80 73 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 85 86 13 10 3 2 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 80 84 87 88 89 81 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 68 71 92 93 77 69 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 25 22 15 14 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 94 57 44 43 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 75 78 83 76 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 55 59 70 56 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 85 86 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 90 91 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 87 88 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 92 93 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 96 97 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 8 19 29 9 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 31 48 60 32 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 62 74 79 63 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 81 89 100 82 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 1 2 3 4 5 0 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 25 27 28 23 22 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 91 42 39 27 90 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 94 96 97 58 57 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 98 99 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 0 1 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 5 6 99 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 0 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 1 2 3 4 5 0 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 25 27 28 23 22 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 91 42 39 27 90 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 94 96 97 58 57 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 98 99 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 0 1 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 5 6 99 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 0 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 2 3 4 5 99 98 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 90 91 42 39 28 23 22 25 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 90 91 42 39 28 23 22 25 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 2 3 4 5 99 98 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 5 6 99 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 25 27 28 23 22 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 94 96 97 58 57 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 0 5 6 99 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 98 99 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 0 1 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 1 2 3 4 5 0 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 25 27 28 23 22 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 94 96 97 58 57 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 1 2 3 4 5 99 0 98 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 5 6 98 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 1 2 3 4 5 99 98 +##! HIGHLIGHT TARGET=QUBIT QUBITS=26,95 COLOR=red +CX 81 82 50 46 57 94 52 49 59 55 39 27 35 36 44 45 56 53 14 13 97 96 93 77 40 41 10 3 1 0 74 79 68 69 64 65 25 22 24 20 18 19 43 42 84 80 4 5 85 2 87 88 6 99 28 23 76 72 37 38 89 100 54 51 15 16 47 48 33 34 21 17 78 75 70 71 11 12 66 67 62 63 30 31 7 8 +TICK +CX 42 39 12 7 3 4 38 35 31 32 77 78 8 9 65 61 49 50 17 18 45 40 28 27 48 60 71 68 55 56 73 74 67 64 63 79 5 6 51 52 46 47 23 24 34 30 2 1 36 33 92 93 13 10 58 97 19 29 88 89 98 99 20 21 69 66 22 15 86 85 80 81 75 76 91 90 53 54 41 37 16 11 +TICK +CX 51 38 77 69 50 64 23 22 17 12 29 32 83 76 53 41 62 74 24 35 20 16 47 61 73 80 42 91 21 33 52 66 14 15 19 8 10 11 70 56 13 86 3 2 81 89 58 57 4 7 46 34 18 30 48 31 92 71 82 100 39 40 75 67 28 25 55 45 6 9 54 68 +TICK +MX 0 1 3 5 13 17 19 20 23 28 42 46 48 51 53 55 58 62 73 75 77 81 87 91 92 97 98 +MZ 7 9 11 15 30 32 33 35 40 56 61 64 66 68 76 79 85 88 89 90 93 96 100 +TICK +RX 0 1 3 5 13 17 19 20 23 28 42 46 48 51 53 55 58 62 73 75 77 81 87 91 92 97 98 +R 7 9 11 15 30 32 33 35 40 56 61 64 66 68 76 79 85 88 89 90 93 96 100 +TICK +CX 51 38 77 69 50 64 23 22 17 12 29 32 83 76 53 41 62 74 24 35 20 16 47 61 73 80 42 91 21 33 52 66 14 15 19 8 10 11 70 56 13 86 3 2 81 89 58 57 4 7 46 34 18 30 48 31 92 71 82 100 39 40 75 67 28 25 55 45 6 9 54 68 +TICK +CX 42 39 12 7 3 4 38 35 31 32 77 78 8 9 65 61 49 50 17 18 45 40 28 27 48 60 71 68 55 56 73 74 67 64 63 79 5 6 51 52 46 47 23 24 34 30 2 1 36 33 92 93 13 10 58 97 19 29 88 89 98 99 20 21 69 66 22 15 86 85 80 81 75 76 91 90 53 54 41 37 16 11 +TICK +CX 81 82 50 46 57 94 52 49 59 55 39 27 35 36 44 45 56 53 14 13 97 96 93 77 40 41 10 3 1 0 74 79 68 69 64 65 25 22 24 20 18 19 43 42 84 80 4 5 85 2 87 88 6 99 28 23 76 72 37 38 89 100 54 51 15 16 47 48 33 34 21 17 78 75 70 71 11 12 66 67 62 63 30 31 7 8 +TICK +CX 41 40 81 82 57 94 72 76 5 4 69 68 3 10 23 28 97 96 77 93 17 21 19 18 65 64 74 73 75 78 53 56 55 59 38 37 84 83 22 25 46 50 48 47 0 1 49 52 34 33 89 100 62 61 27 39 16 15 42 43 12 11 67 66 51 54 20 24 31 30 8 7 99 6 36 35 45 44 2 85 +TICK +CX 32 31 90 91 18 17 4 3 59 58 78 77 44 57 39 42 9 8 49 50 66 69 27 28 47 46 93 92 6 5 24 23 88 87 56 55 29 19 52 51 67 64 35 38 1 2 36 33 68 71 79 74 60 48 7 12 15 22 20 21 61 65 80 84 40 45 10 13 75 76 85 86 53 54 73 72 63 62 41 37 16 11 30 34 +TICK +CX 22 23 69 77 30 18 7 4 67 49 34 46 41 27 15 14 25 28 37 54 45 55 86 13 56 70 62 74 71 92 33 50 80 73 65 72 63 60 91 42 32 29 61 47 98 99 81 89 44 43 64 76 12 17 66 52 36 20 82 100 57 58 9 6 40 39 38 51 2 3 8 19 11 21 31 48 35 24 +TICK +MX 7 9 15 30 32 35 36 40 41 44 56 61 63 66 67 80 81 85 88 90 93 97 +MZ 0 1 3 5 13 17 19 21 23 28 42 46 48 50 51 54 55 58 72 74 76 77 87 91 92 96 99 100 +TICK +RX 7 9 15 30 32 35 36 40 41 44 56 61 63 66 67 80 81 85 88 90 93 97 +R 0 1 3 5 13 17 19 21 23 28 42 46 48 50 51 54 55 58 72 74 76 77 87 91 92 96 99 100 +TICK +CX 22 23 69 77 30 18 7 4 67 49 34 46 41 27 15 14 25 28 37 54 45 55 86 13 56 70 62 74 71 92 33 50 80 73 65 72 63 60 91 42 32 29 61 47 98 99 81 89 44 43 64 76 12 17 66 52 36 20 82 100 57 58 9 6 40 39 38 51 2 3 8 19 11 21 31 48 35 24 +TICK +CX 32 31 90 91 18 17 4 3 59 58 78 77 44 57 39 42 9 8 49 50 66 69 27 28 47 46 93 92 6 5 24 23 88 87 56 55 29 19 52 51 67 64 35 38 1 2 36 33 68 71 79 74 60 48 7 12 15 22 20 21 61 65 80 84 40 45 10 13 75 76 85 86 53 54 73 72 63 62 41 37 16 11 30 34 +TICK +CX 41 40 81 82 57 94 72 76 5 4 69 68 3 10 23 28 97 96 77 93 17 21 19 18 65 64 74 73 75 78 53 56 55 59 38 37 84 83 22 25 46 50 48 47 0 1 49 52 34 33 89 100 62 61 27 39 16 15 42 43 12 11 67 66 51 54 20 24 31 30 8 7 99 6 36 35 45 44 2 85 +TICK +CX 32 31 50 49 18 17 33 36 58 59 82 81 39 27 5 4 3 10 77 78 100 89 40 41 13 14 47 46 71 68 24 23 88 87 45 55 96 97 29 19 56 70 94 57 51 52 22 25 0 1 92 93 79 74 16 15 60 48 12 11 43 44 69 66 67 75 21 20 61 65 80 84 37 28 53 54 63 62 76 83 73 72 30 34 +TICK +CX 42 39 50 46 4 3 44 45 23 22 93 77 9 8 19 18 74 73 28 27 68 69 66 78 15 14 64 65 55 56 53 71 38 37 5 6 48 47 89 88 1 2 83 84 11 16 62 61 54 51 7 12 81 80 99 98 33 34 21 17 31 30 36 20 57 58 10 13 75 76 91 90 85 86 35 24 +TICK +CX 59 55 69 77 23 28 68 54 79 63 75 78 7 4 50 33 24 20 47 61 73 80 72 84 35 38 57 44 100 82 46 65 11 10 97 58 29 9 18 30 48 31 22 15 89 81 74 62 99 6 2 3 8 19 60 32 17 34 42 91 56 53 27 41 +TICK +MX 7 11 22 23 29 35 42 48 50 56 57 59 60 68 74 75 79 85 88 89 91 92 96 100 +MZ 0 1 3 6 19 20 30 31 34 41 44 58 61 62 65 77 78 80 81 84 86 87 90 93 97 98 +TICK +RX 7 11 22 23 29 35 42 48 50 56 57 59 60 68 74 75 79 85 88 89 91 92 96 100 +R 0 1 3 6 19 20 30 31 34 41 44 58 61 62 65 77 78 80 81 84 86 87 90 93 97 98 +TICK +CX 59 55 69 77 23 28 68 54 79 63 75 78 7 4 50 33 24 20 47 61 73 80 72 84 35 38 57 44 100 82 46 65 11 10 97 58 29 9 18 30 48 31 22 15 89 81 74 62 99 6 2 3 8 19 60 32 17 34 42 91 56 53 27 41 +TICK +CX 42 39 50 46 4 3 44 45 23 22 93 77 9 8 19 18 74 73 28 27 68 69 66 78 15 14 64 65 55 56 53 71 38 37 5 6 48 47 89 88 1 2 83 84 11 16 62 61 54 51 7 12 81 80 99 98 33 34 21 17 31 30 36 20 57 58 10 13 75 76 91 90 85 86 35 24 +TICK +CX 32 31 50 49 18 17 33 36 58 59 82 81 39 27 5 4 3 10 77 78 100 89 40 41 13 14 47 46 71 68 24 23 88 87 45 55 96 97 29 19 56 70 94 57 51 52 22 25 0 1 92 93 79 74 16 15 60 48 12 11 43 44 69 66 67 75 21 20 61 65 80 84 37 28 53 54 63 62 76 83 73 72 30 34 +TICK diff --git a/visualisations/colour_square_deg4_d7_dropQ2_dropE4_L4_R1.stim b/visualisations/colour_square_deg4_d7_dropQ2_dropE4_L4_R1.stim new file mode 100644 index 0000000..ee63dc4 --- /dev/null +++ b/visualisations/colour_square_deg4_d7_dropQ2_dropE4_L4_R1.stim @@ -0,0 +1,530 @@ +# Legend +# Qubits: L (c=0) = gold, R (c=1) = mediumseagreen +# Connections by class (name: colour): +# - E: #4361ee +##! EMBEDDING TYPE=PLANE LX=11 LY=16 +##! SHEET NAME=QUBITS Z=0 +##! SHEET NAME=E Z=1 +##! SHEET NAME=UNTX Z=2 +##! SHEET NAME=UNTZ Z=3 +##! SHEET NAME=ANTIX Z=4 +##! SHEET NAME=ANTIZ Z=5 +##! SHEET NAME=PRODX Z=6 +##! SHEET NAME=PRODZ Z=7 +##! SHEET NAME=GAUGEX Z=8 +##! SHEET NAME=GAUGEZ Z=9 +##! QUBIT Q=0 SHEET=QUBITS X=1 Y=1 COLOUR=gold +QUBIT_COORDS(1, 1) 0 +##! QUBIT Q=1 SHEET=QUBITS X=1 Y=2 COLOUR=gold +QUBIT_COORDS(1, 2) 1 +##! QUBIT Q=2 SHEET=QUBITS X=1 Y=3 COLOUR=gold +QUBIT_COORDS(1, 3) 2 +##! QUBIT Q=3 SHEET=QUBITS X=2 Y=3 COLOUR=gold +QUBIT_COORDS(2, 3) 3 +##! QUBIT Q=4 SHEET=QUBITS X=2 Y=2 COLOUR=gold +QUBIT_COORDS(2, 2) 4 +##! QUBIT Q=5 SHEET=QUBITS X=2 Y=1 COLOUR=gold +QUBIT_COORDS(2, 1) 5 +##! QUBIT Q=6 SHEET=QUBITS X=2 Y=0 COLOUR=gold +QUBIT_COORDS(2, 0) 6 +##! QUBIT Q=7 SHEET=QUBITS X=3 Y=2 COLOUR=gold +QUBIT_COORDS(3, 2) 7 +##! QUBIT Q=8 SHEET=QUBITS X=3 Y=1 COLOUR=gold +QUBIT_COORDS(3, 1) 8 +##! QUBIT Q=9 SHEET=QUBITS X=3 Y=0 COLOUR=gold +QUBIT_COORDS(3, 0) 9 +##! QUBIT Q=10 SHEET=QUBITS X=2 Y=4 COLOUR=gold +QUBIT_COORDS(2, 4) 10 +##! QUBIT Q=11 SHEET=QUBITS X=3 Y=4 COLOUR=gold +QUBIT_COORDS(3, 4) 11 +##! QUBIT Q=12 SHEET=QUBITS X=3 Y=3 COLOUR=gold +QUBIT_COORDS(3, 3) 12 +##! QUBIT Q=13 SHEET=QUBITS X=2 Y=5 COLOUR=gold +QUBIT_COORDS(2, 5) 13 +##! QUBIT Q=14 SHEET=QUBITS X=2 Y=6 COLOUR=gold +QUBIT_COORDS(2, 6) 14 +##! QUBIT Q=15 SHEET=QUBITS X=3 Y=6 COLOUR=gold +QUBIT_COORDS(3, 6) 15 +##! QUBIT Q=16 SHEET=QUBITS X=3 Y=5 COLOUR=gold +QUBIT_COORDS(3, 5) 16 +##! QUBIT Q=17 SHEET=QUBITS X=4 Y=3 COLOUR=gold +QUBIT_COORDS(4, 3) 17 +##! QUBIT Q=18 SHEET=QUBITS X=4 Y=2 COLOUR=gold +QUBIT_COORDS(4, 2) 18 +##! QUBIT Q=19 SHEET=QUBITS X=4 Y=1 COLOUR=gold +QUBIT_COORDS(4, 1) 19 +##! QUBIT Q=20 SHEET=QUBITS X=4 Y=5 COLOUR=gold +QUBIT_COORDS(4, 5) 20 +##! QUBIT Q=21 SHEET=QUBITS X=4 Y=4 COLOUR=gold +QUBIT_COORDS(4, 4) 21 +##! QUBIT Q=22 SHEET=QUBITS X=3 Y=7 COLOUR=gold +QUBIT_COORDS(3, 7) 22 +##! QUBIT Q=23 SHEET=QUBITS X=4 Y=7 COLOUR=gold +QUBIT_COORDS(4, 7) 23 +##! QUBIT Q=24 SHEET=QUBITS X=4 Y=6 COLOUR=gold +QUBIT_COORDS(4, 6) 24 +##! QUBIT Q=25 SHEET=QUBITS X=3 Y=8 COLOUR=gold +QUBIT_COORDS(3, 8) 25 +##! QUBIT Q=26 SHEET=QUBITS X=3 Y=9 COLOUR=gold +QUBIT_COORDS(3, 9) 26 +##! QUBIT Q=27 SHEET=QUBITS X=4 Y=9 COLOUR=gold +QUBIT_COORDS(4, 9) 27 +##! QUBIT Q=28 SHEET=QUBITS X=4 Y=8 COLOUR=gold +QUBIT_COORDS(4, 8) 28 +##! QUBIT Q=29 SHEET=QUBITS X=4 Y=0 COLOUR=gold +QUBIT_COORDS(4, 0) 29 +##! QUBIT Q=30 SHEET=QUBITS X=5 Y=2 COLOUR=gold +QUBIT_COORDS(5, 2) 30 +##! QUBIT Q=31 SHEET=QUBITS X=5 Y=1 COLOUR=gold +QUBIT_COORDS(5, 1) 31 +##! QUBIT Q=32 SHEET=QUBITS X=5 Y=0 COLOUR=gold +QUBIT_COORDS(5, 0) 32 +##! QUBIT Q=33 SHEET=QUBITS X=5 Y=4 COLOUR=gold +QUBIT_COORDS(5, 4) 33 +##! QUBIT Q=34 SHEET=QUBITS X=5 Y=3 COLOUR=gold +QUBIT_COORDS(5, 3) 34 +##! QUBIT Q=35 SHEET=QUBITS X=5 Y=6 COLOUR=gold +QUBIT_COORDS(5, 6) 35 +##! QUBIT Q=36 SHEET=QUBITS X=5 Y=5 COLOUR=gold +QUBIT_COORDS(5, 5) 36 +##! QUBIT Q=37 SHEET=QUBITS X=5 Y=8 COLOUR=gold +QUBIT_COORDS(5, 8) 37 +##! QUBIT Q=38 SHEET=QUBITS X=5 Y=7 COLOUR=gold +QUBIT_COORDS(5, 7) 38 +##! QUBIT Q=39 SHEET=QUBITS X=4 Y=10 COLOUR=gold +QUBIT_COORDS(4, 10) 39 +##! QUBIT Q=40 SHEET=QUBITS X=5 Y=10 COLOUR=gold +QUBIT_COORDS(5, 10) 40 +##! QUBIT Q=41 SHEET=QUBITS X=5 Y=9 COLOUR=gold +QUBIT_COORDS(5, 9) 41 +##! QUBIT Q=42 SHEET=QUBITS X=4 Y=11 COLOUR=gold +QUBIT_COORDS(4, 11) 42 +##! QUBIT Q=43 SHEET=QUBITS X=4 Y=12 COLOUR=gold +QUBIT_COORDS(4, 12) 43 +##! QUBIT Q=44 SHEET=QUBITS X=5 Y=12 COLOUR=gold +QUBIT_COORDS(5, 12) 44 +##! QUBIT Q=45 SHEET=QUBITS X=5 Y=11 COLOUR=gold +QUBIT_COORDS(5, 11) 45 +##! QUBIT Q=46 SHEET=QUBITS X=6 Y=3 COLOUR=gold +QUBIT_COORDS(6, 3) 46 +##! QUBIT Q=47 SHEET=QUBITS X=6 Y=2 COLOUR=gold +QUBIT_COORDS(6, 2) 47 +##! QUBIT Q=48 SHEET=QUBITS X=6 Y=1 COLOUR=gold +QUBIT_COORDS(6, 1) 48 +##! QUBIT Q=49 SHEET=QUBITS X=6 Y=5 COLOUR=gold +QUBIT_COORDS(6, 5) 49 +##! QUBIT Q=50 SHEET=QUBITS X=6 Y=4 COLOUR=gold +QUBIT_COORDS(6, 4) 50 +##! QUBIT Q=51 SHEET=QUBITS X=6 Y=7 COLOUR=gold +QUBIT_COORDS(6, 7) 51 +##! QUBIT Q=52 SHEET=QUBITS X=6 Y=6 COLOUR=gold +QUBIT_COORDS(6, 6) 52 +##! QUBIT Q=53 SHEET=QUBITS X=6 Y=9 COLOUR=gold +QUBIT_COORDS(6, 9) 53 +##! QUBIT Q=54 SHEET=QUBITS X=6 Y=8 COLOUR=gold +QUBIT_COORDS(6, 8) 54 +##! QUBIT Q=55 SHEET=QUBITS X=6 Y=11 COLOUR=gold +QUBIT_COORDS(6, 11) 55 +##! QUBIT Q=56 SHEET=QUBITS X=6 Y=10 COLOUR=gold +QUBIT_COORDS(6, 10) 56 +##! QUBIT Q=57 SHEET=QUBITS X=5 Y=13 COLOUR=gold +QUBIT_COORDS(5, 13) 57 +##! QUBIT Q=58 SHEET=QUBITS X=6 Y=13 COLOUR=gold +QUBIT_COORDS(6, 13) 58 +##! QUBIT Q=59 SHEET=QUBITS X=6 Y=12 COLOUR=gold +QUBIT_COORDS(6, 12) 59 +##! QUBIT Q=60 SHEET=QUBITS X=6 Y=0 COLOUR=gold +QUBIT_COORDS(6, 0) 60 +##! QUBIT Q=61 SHEET=QUBITS X=7 Y=2 COLOUR=gold +QUBIT_COORDS(7, 2) 61 +##! QUBIT Q=62 SHEET=QUBITS X=7 Y=1 COLOUR=gold +QUBIT_COORDS(7, 1) 62 +##! QUBIT Q=63 SHEET=QUBITS X=7 Y=0 COLOUR=gold +QUBIT_COORDS(7, 0) 63 +##! QUBIT Q=64 SHEET=QUBITS X=7 Y=4 COLOUR=gold +QUBIT_COORDS(7, 4) 64 +##! QUBIT Q=65 SHEET=QUBITS X=7 Y=3 COLOUR=gold +QUBIT_COORDS(7, 3) 65 +##! HIGHLIGHT TARGET=QUBIT QUBITS=66 COLOR=red +##! QUBIT Q=66 SHEET=QUBITS X=7 Y=6 COLOUR=gold DEFECTIVE=true +QUBIT_COORDS(7, 6) 66 +##! QUBIT Q=67 SHEET=QUBITS X=7 Y=5 COLOUR=gold +QUBIT_COORDS(7, 5) 67 +##! QUBIT Q=68 SHEET=QUBITS X=7 Y=8 COLOUR=gold +QUBIT_COORDS(7, 8) 68 +##! QUBIT Q=69 SHEET=QUBITS X=7 Y=7 COLOUR=gold +QUBIT_COORDS(7, 7) 69 +##! QUBIT Q=70 SHEET=QUBITS X=7 Y=10 COLOUR=gold +QUBIT_COORDS(7, 10) 70 +##! QUBIT Q=71 SHEET=QUBITS X=7 Y=9 COLOUR=gold +QUBIT_COORDS(7, 9) 71 +##! QUBIT Q=72 SHEET=QUBITS X=8 Y=3 COLOUR=gold +QUBIT_COORDS(8, 3) 72 +##! QUBIT Q=73 SHEET=QUBITS X=8 Y=2 COLOUR=gold +QUBIT_COORDS(8, 2) 73 +##! QUBIT Q=74 SHEET=QUBITS X=8 Y=1 COLOUR=gold +QUBIT_COORDS(8, 1) 74 +##! HIGHLIGHT TARGET=QUBIT QUBITS=75 COLOR=red +##! QUBIT Q=75 SHEET=QUBITS X=8 Y=5 COLOUR=gold DEFECTIVE=true +QUBIT_COORDS(8, 5) 75 +##! QUBIT Q=76 SHEET=QUBITS X=8 Y=4 COLOUR=gold +QUBIT_COORDS(8, 4) 76 +##! QUBIT Q=77 SHEET=QUBITS X=8 Y=7 COLOUR=gold +QUBIT_COORDS(8, 7) 77 +##! QUBIT Q=78 SHEET=QUBITS X=8 Y=6 COLOUR=gold +QUBIT_COORDS(8, 6) 78 +##! QUBIT Q=79 SHEET=QUBITS X=8 Y=0 COLOUR=gold +QUBIT_COORDS(8, 0) 79 +##! QUBIT Q=80 SHEET=QUBITS X=9 Y=2 COLOUR=gold +QUBIT_COORDS(9, 2) 80 +##! QUBIT Q=81 SHEET=QUBITS X=9 Y=1 COLOUR=gold +QUBIT_COORDS(9, 1) 81 +##! QUBIT Q=82 SHEET=QUBITS X=9 Y=0 COLOUR=gold +QUBIT_COORDS(9, 0) 82 +##! QUBIT Q=83 SHEET=QUBITS X=9 Y=4 COLOUR=gold +QUBIT_COORDS(9, 4) 83 +##! QUBIT Q=84 SHEET=QUBITS X=9 Y=3 COLOUR=gold +QUBIT_COORDS(9, 3) 84 +##! QUBIT Q=85 SHEET=QUBITS X=1 Y=4 COLOUR=gold +QUBIT_COORDS(1, 4) 85 +##! QUBIT Q=86 SHEET=QUBITS X=1 Y=5 COLOUR=gold +QUBIT_COORDS(1, 5) 86 +##! QUBIT Q=87 SHEET=QUBITS X=10 Y=3 COLOUR=gold +QUBIT_COORDS(10, 3) 87 +##! QUBIT Q=88 SHEET=QUBITS X=10 Y=2 COLOUR=gold +QUBIT_COORDS(10, 2) 88 +##! QUBIT Q=89 SHEET=QUBITS X=10 Y=1 COLOUR=gold +QUBIT_COORDS(10, 1) 89 +##! QUBIT Q=90 SHEET=QUBITS X=3 Y=10 COLOUR=gold +QUBIT_COORDS(3, 10) 90 +##! QUBIT Q=91 SHEET=QUBITS X=3 Y=11 COLOUR=gold +QUBIT_COORDS(3, 11) 91 +##! QUBIT Q=92 SHEET=QUBITS X=8 Y=9 COLOUR=gold +QUBIT_COORDS(8, 9) 92 +##! QUBIT Q=93 SHEET=QUBITS X=8 Y=8 COLOUR=gold +QUBIT_COORDS(8, 8) 93 +##! QUBIT Q=94 SHEET=QUBITS X=5 Y=14 COLOUR=gold +QUBIT_COORDS(5, 14) 94 +##! QUBIT Q=95 SHEET=QUBITS X=5 Y=15 COLOUR=gold +QUBIT_COORDS(5, 15) 95 +##! QUBIT Q=96 SHEET=QUBITS X=6 Y=15 COLOUR=gold +QUBIT_COORDS(6, 15) 96 +##! QUBIT Q=97 SHEET=QUBITS X=6 Y=14 COLOUR=gold +QUBIT_COORDS(6, 14) 97 +##! QUBIT Q=98 SHEET=QUBITS X=0 Y=0 COLOUR=gold +QUBIT_COORDS(0, 0) 98 +##! QUBIT Q=99 SHEET=QUBITS X=1 Y=0 COLOUR=gold +QUBIT_COORDS(1, 0) 99 +##! QUBIT Q=100 SHEET=QUBITS X=10 Y=0 COLOUR=gold +QUBIT_COORDS(10, 0) 100 +##! CONN SET SHEET=E EDGES=(0-1,0-5,0-99,1-2,1-4,2-3,2-85,3-4,3-10,3-12,4-5,4-7,5-6,5-8,6-9,6-99,7-8,7-18,8-9,8-19,9-29,10-11,10-13,11-12,11-16,11-21,12-17,13-14,13-16,13-86,14-15,15-16,15-22,15-24,16-20,17-18,17-21,17-34,18-19,18-30,19-29,19-31,20-21,20-24,20-36,21-33,22-23,22-25,23-24,23-28,23-38,24-35,25-26,25-28,26-27,26-90,27-28,27-41,28-37,29-32,30-31,30-34,30-47,31-32,31-48,32-60,33-34,33-36,33-50,34-46,35-36,35-38,35-52,36-49,37-38,37-41,37-54,38-51,39-40,39-42,39-90,40-41,40-45,40-56,41-53,42-43,42-45,42-91,43-44,44-45,44-57,44-59,45-55,46-47,46-50,46-65,47-48,47-61,48-60,48-62,49-50,49-52,49-67,50-64,51-52,51-54,51-69,52-66,53-54,53-56,53-71,54-68,55-56,55-59,56-70,57-58,57-94,58-59,58-97,60-63,61-62,61-65,61-73,62-63,62-74,63-79,64-65,64-67,64-76,65-72,66-67,66-69,66-78,67-75,68-69,68-71,68-93,69-77,70-71,71-92,72-76,72-84,73-74,73-80,74-79,74-81,75-76,75-78,76-83,77-78,77-93,79-82,80-81,80-84,80-88,81-82,81-89,82-100,83-84,84-87,85-86,87-88,88-89,89-100,90-91,92-93,94-95,94-97,95-96,96-97,98-99) THICKNESS=2 COLOUR=#4361ee +##! CONN SET SHEET=E EDGES=(7-12,10-85,27-39,72-73) THICKNESS=2 COLOUR=red +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 1 2 3 4 5 0 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 5 4 7 8 9 6 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 3 10 11 12 7 4 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 13 14 15 16 11 10 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 7 12 17 18 19 8 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 11 16 20 21 17 12 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 15 22 23 24 20 16 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 25 26 27 28 23 22 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 19 18 30 31 32 29 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 17 21 33 34 30 18 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 20 24 35 36 33 21 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 23 28 37 38 35 24 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 27 39 40 41 37 28 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 42 43 44 45 40 39 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 30 34 46 47 48 31 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 33 36 49 50 46 34 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 35 38 51 52 49 36 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 37 41 53 54 51 38 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 40 45 55 56 53 41 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 44 57 58 59 55 45 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 48 47 61 62 63 60 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 46 50 64 65 61 47 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 53 56 70 71 68 54 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 61 65 72 73 74 62 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 74 73 80 81 82 79 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 72 76 83 84 80 73 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 85 86 13 10 3 2 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 80 84 87 88 89 81 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 90 91 42 39 27 26 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 68 71 92 93 77 69 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 94 95 96 97 58 57 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 1 0 99 98 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 25 22 15 14 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 94 57 44 43 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 55 59 70 56 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 85 86 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 90 91 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 87 88 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 92 93 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 96 97 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 0 5 6 99 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 8 19 29 9 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 31 48 60 32 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 62 74 79 63 +##! POLY SHEET=UNTX +#!pragma POLYGON(1,0,0,0.15) 81 89 100 82 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 1 2 3 4 5 0 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 5 4 7 8 9 6 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 3 10 11 12 7 4 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 13 14 15 16 11 10 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 7 12 17 18 19 8 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 11 16 20 21 17 12 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 15 22 23 24 20 16 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 25 26 27 28 23 22 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 19 18 30 31 32 29 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 17 21 33 34 30 18 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 20 24 35 36 33 21 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 23 28 37 38 35 24 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 27 39 40 41 37 28 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 42 43 44 45 40 39 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 30 34 46 47 48 31 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 33 36 49 50 46 34 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 35 38 51 52 49 36 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 37 41 53 54 51 38 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 40 45 55 56 53 41 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 44 57 58 59 55 45 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 48 47 61 62 63 60 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 46 50 64 65 61 47 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 53 56 70 71 68 54 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 61 65 72 73 74 62 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 74 73 80 81 82 79 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 72 76 83 84 80 73 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 85 86 13 10 3 2 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 80 84 87 88 89 81 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 90 91 42 39 27 26 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 68 71 92 93 77 69 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 94 95 96 97 58 57 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 1 0 99 98 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 25 22 15 14 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 94 57 44 43 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 55 59 70 56 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 85 86 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 90 91 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 87 88 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 92 93 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 96 97 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 0 5 6 99 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 8 19 29 9 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 31 48 60 32 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 62 74 79 63 +##! POLY SHEET=UNTZ +#!pragma POLYGON(0,0,1,0.15) 81 89 100 82 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 49 52 67 64 50 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 54 68 69 52 51 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 64 67 76 72 65 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 67 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 69 77 78 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 76 83 +##! POLY SHEET=ANTIX +#!pragma POLYGON(1,0,0,0.15) 78 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 49 52 67 64 50 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 54 68 69 52 51 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 64 67 76 72 65 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 67 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 69 77 78 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 76 83 +##! POLY SHEET=ANTIZ +#!pragma POLYGON(0,0,1,0.15) 78 +##! POLY SHEET=PRODX +#!pragma POLYGON(1,0,0,0.15) 52 69 77 83 76 64 50 49 +##! POLY SHEET=PRODZ +#!pragma POLYGON(0,0,1,0.15) 52 69 77 83 76 64 50 49 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 49 52 67 64 50 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 49 52 64 50 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 64 67 76 72 65 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 51 54 68 69 67 64 50 49 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 51 54 68 69 83 72 65 50 49 +##! POLY SHEET=GAUGEX +#!pragma POLYGON(1,0,0,0.15) 52 51 54 68 77 78 76 72 65 64 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 49 52 67 64 50 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 51 54 68 69 67 64 50 49 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 51 54 68 69 76 72 65 50 49 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 52 51 54 68 69 76 72 64 65 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 52 51 54 68 77 78 76 72 65 64 +##! POLY SHEET=GAUGEZ +#!pragma POLYGON(0,0,1,0.15) 52 69 77 78 83 76 64 50 49 +##! HIGHLIGHT TARGET=QUBIT QUBITS=66,75 COLOR=red +CX 32 31 41 40 57 94 26 27 3 10 95 96 23 28 9 8 17 21 65 64 13 14 53 56 71 68 55 59 29 19 73 80 72 84 38 37 5 0 22 25 87 88 46 50 6 99 49 52 34 33 92 93 58 97 79 74 16 15 60 48 61 47 42 43 12 11 18 30 51 54 20 24 36 35 45 44 91 90 63 62 76 83 +TICK +CX 50 49 33 36 59 58 77 69 93 68 44 57 39 42 65 61 27 28 24 23 56 55 96 97 52 51 35 38 3 12 0 1 83 84 11 16 71 70 99 98 15 22 64 67 81 89 4 7 21 20 82 100 40 45 10 13 62 48 53 54 17 34 19 31 41 37 +TICK +CX 81 82 3 4 69 68 22 23 77 78 79 63 17 18 71 53 64 50 94 97 36 49 15 14 6 5 25 28 37 54 45 55 0 99 62 74 56 70 20 16 84 80 48 47 46 65 11 10 89 100 29 9 44 43 86 85 57 58 40 39 38 51 8 19 60 32 33 21 30 31 35 24 +TICK +MX 0 3 6 11 15 17 29 33 35 40 44 46 56 60 64 67 71 76 77 78 79 81 86 87 91 92 96 +MZ 16 19 23 28 31 47 49 51 54 55 58 68 74 80 83 85 88 90 93 97 99 100 +TICK +RX 0 3 6 11 15 17 29 33 35 40 44 46 56 60 64 67 71 76 77 78 79 81 86 87 91 92 96 +R 16 19 23 28 31 47 49 51 54 55 58 68 74 80 83 85 88 90 93 97 99 100 +TICK +CX 81 82 3 4 69 68 22 23 77 78 79 63 17 18 71 53 64 50 94 97 36 49 15 14 6 5 25 28 37 54 45 55 0 99 62 74 56 70 20 16 84 80 48 47 46 65 11 10 89 100 29 9 44 43 86 85 57 58 40 39 38 51 8 19 60 32 33 21 30 31 35 24 +TICK +CX 50 49 33 36 59 58 77 69 93 68 44 57 39 42 65 61 27 28 24 23 56 55 96 97 52 51 35 38 3 12 0 1 83 84 11 16 71 70 99 98 15 22 64 67 81 89 4 7 21 20 82 100 40 45 10 13 62 48 53 54 17 34 19 31 41 37 +TICK +CX 32 31 41 40 57 94 26 27 3 10 95 96 23 28 9 8 17 21 65 64 13 14 53 56 71 68 55 59 29 19 73 80 72 84 38 37 5 0 22 25 87 88 46 50 6 99 49 52 34 33 92 93 58 97 79 74 16 15 60 48 61 47 42 43 12 11 18 30 51 54 20 24 36 35 45 44 91 90 63 62 76 83 +TICK +CX 50 46 59 55 52 49 26 27 35 36 44 45 69 77 14 13 9 8 40 41 10 3 30 18 83 76 0 5 74 79 48 60 7 4 64 65 25 22 24 20 96 97 47 61 43 42 31 19 28 23 37 38 68 71 54 51 15 16 32 29 33 34 21 17 57 58 99 6 11 12 62 63 84 72 56 53 +TICK +CX 42 39 18 17 4 3 38 35 78 77 31 32 95 96 49 50 1 0 45 40 68 69 93 92 55 56 29 19 67 64 84 83 51 52 94 57 80 73 23 24 46 65 36 33 13 10 48 62 37 41 98 99 43 44 81 89 20 21 70 71 22 15 82 100 91 90 85 86 54 53 16 11 25 26 +TICK +CX 51 38 16 20 81 82 50 64 23 22 44 57 54 37 65 61 19 18 24 35 53 71 63 79 68 93 5 6 3 12 21 33 14 15 87 88 32 60 10 11 89 100 29 9 47 48 70 56 49 36 31 30 95 94 74 62 39 40 80 84 99 0 28 25 55 45 17 34 +TICK +MX 16 23 28 29 31 47 49 51 54 55 68 74 80 81 83 85 87 91 93 95 96 99 +MZ 0 6 11 12 15 18 33 34 35 40 56 57 60 61 64 67 71 76 77 78 79 86 88 90 92 97 100 +TICK +RX 16 23 28 29 31 47 49 51 54 55 68 74 80 81 83 85 87 91 93 95 96 99 +R 0 6 11 12 15 18 33 34 35 40 56 57 60 61 64 67 71 76 77 78 79 86 88 90 92 97 100 +TICK +CX 51 38 16 20 81 82 50 64 23 22 44 57 54 37 65 61 19 18 24 35 53 71 63 79 68 93 5 6 3 12 21 33 14 15 87 88 32 60 10 11 89 100 29 9 47 48 70 56 49 36 31 30 95 94 74 62 39 40 80 84 99 0 28 25 55 45 17 34 +TICK +CX 42 39 18 17 4 3 38 35 78 77 31 32 95 96 49 50 1 0 45 40 68 69 93 92 55 56 29 19 67 64 84 83 51 52 94 57 80 73 23 24 46 65 36 33 13 10 48 62 37 41 98 99 43 44 81 89 20 21 70 71 22 15 82 100 91 90 85 86 54 53 16 11 25 26 +TICK +CX 50 46 59 55 52 49 26 27 35 36 44 45 69 77 14 13 9 8 40 41 10 3 30 18 83 76 0 5 74 79 48 60 7 4 64 65 25 22 24 20 96 97 47 61 43 42 31 19 28 23 37 38 68 71 54 51 15 16 32 29 33 34 21 17 57 58 99 6 11 12 62 63 84 72 56 53 +TICK +CX 90 91 26 27 5 4 77 69 68 54 97 96 17 21 19 18 74 73 83 76 53 41 93 92 88 87 56 55 22 25 46 50 48 47 0 1 49 52 34 33 62 61 71 70 72 65 16 15 99 98 64 67 12 11 3 2 58 57 20 24 31 30 86 85 89 81 8 7 40 39 38 51 36 35 45 44 28 37 79 82 +TICK +CX 41 40 50 49 96 95 33 36 57 94 59 58 69 68 31 32 8 9 39 42 65 61 10 3 76 64 74 79 27 28 48 60 47 46 24 23 90 26 0 99 5 6 51 52 100 82 11 16 19 29 70 56 81 80 13 86 15 22 7 18 44 43 4 1 62 63 87 84 21 20 12 17 92 71 55 45 54 53 30 34 +TICK +CX 72 76 22 23 77 78 61 73 100 89 17 18 64 50 53 56 9 29 41 27 36 49 15 14 55 59 20 16 63 79 31 19 57 44 39 90 8 5 32 60 1 2 68 71 81 74 69 51 42 43 46 34 35 52 80 84 99 6 40 45 10 13 62 48 33 21 94 95 +TICK +MX 0 8 10 15 31 33 39 41 55 57 62 64 67 69 72 77 78 81 83 86 88 93 97 100 +MZ 2 6 16 18 23 29 34 43 45 49 52 56 60 71 73 79 84 85 87 91 92 95 96 +TICK +RX 0 8 10 15 31 33 39 41 55 57 62 64 67 69 72 77 78 81 83 86 88 93 97 100 +R 2 6 16 18 23 29 34 43 45 49 52 56 60 71 73 79 84 85 87 91 92 95 96 +TICK +CX 72 76 22 23 77 78 61 73 100 89 17 18 64 50 53 56 9 29 41 27 36 49 15 14 55 59 20 16 63 79 31 19 57 44 39 90 8 5 32 60 1 2 68 71 81 74 69 51 42 43 46 34 35 52 80 84 99 6 40 45 10 13 62 48 33 21 94 95 +TICK +CX 41 40 50 49 96 95 33 36 57 94 59 58 69 68 31 32 8 9 39 42 65 61 10 3 76 64 74 79 27 28 48 60 47 46 24 23 90 26 0 99 5 6 51 52 100 82 11 16 19 29 70 56 81 80 13 86 15 22 7 18 44 43 4 1 62 63 87 84 21 20 12 17 92 71 55 45 54 53 30 34 +TICK +CX 90 91 26 27 5 4 77 69 68 54 97 96 17 21 19 18 74 73 83 76 53 41 93 92 88 87 56 55 22 25 46 50 48 47 0 1 49 52 34 33 62 61 71 70 72 65 16 15 99 98 64 67 12 11 3 2 58 57 20 24 31 30 86 85 89 81 8 7 40 39 38 51 36 35 45 44 28 37 79 82 +TICK +CX 50 46 59 55 52 49 35 36 44 45 56 53 69 77 97 96 1 0 25 22 24 20 18 19 67 64 73 74 4 5 87 88 28 23 65 72 68 71 37 41 54 51 15 16 47 48 33 34 82 79 58 57 81 89 98 99 21 17 61 62 39 40 2 3 11 12 27 26 85 86 91 90 30 31 76 83 7 8 +TICK +CX 32 31 96 95 42 39 57 94 54 53 59 58 84 87 3 10 17 12 9 8 40 41 49 50 28 27 68 69 93 92 18 7 6 5 55 56 86 13 29 19 52 51 26 90 35 38 46 47 23 24 34 30 36 33 79 74 60 48 43 44 64 76 20 21 70 71 22 15 61 65 82 100 99 0 80 81 1 4 63 62 16 11 +TICK +CX 16 20 18 17 90 39 78 77 50 64 23 22 79 63 34 46 53 71 43 42 84 80 68 93 21 33 14 15 6 99 76 72 2 1 89 100 48 62 59 44 73 61 74 81 13 10 52 35 29 9 70 56 49 36 5 8 51 69 94 95 28 25 60 32 19 31 27 41 +TICK +MX 2 6 16 18 23 28 29 34 43 49 52 59 60 68 73 79 84 85 87 91 93 97 +MZ 0 8 10 15 31 33 39 41 56 62 64 67 69 71 72 77 78 81 83 86 88 92 95 96 100 +TICK +RX 2 6 16 18 23 28 29 34 43 49 52 59 60 68 73 79 84 85 87 91 93 97 +R 0 8 10 15 31 33 39 41 56 62 64 67 69 71 72 77 78 81 83 86 88 92 95 96 100 +TICK +CX 16 20 18 17 90 39 78 77 50 64 23 22 79 63 34 46 53 71 43 42 84 80 68 93 21 33 14 15 6 99 76 72 2 1 89 100 48 62 59 44 73 61 74 81 13 10 52 35 29 9 70 56 49 36 5 8 51 69 94 95 28 25 60 32 19 31 27 41 +TICK +CX 32 31 96 95 42 39 57 94 54 53 59 58 84 87 3 10 17 12 9 8 40 41 49 50 28 27 68 69 93 92 18 7 6 5 55 56 86 13 29 19 52 51 26 90 35 38 46 47 23 24 34 30 36 33 79 74 60 48 43 44 64 76 20 21 70 71 22 15 61 65 82 100 99 0 80 81 1 4 63 62 16 11 +TICK +CX 50 46 59 55 52 49 35 36 44 45 56 53 69 77 97 96 1 0 25 22 24 20 18 19 67 64 73 74 4 5 87 88 28 23 65 72 68 71 37 41 54 51 15 16 47 48 33 34 82 79 58 57 81 89 98 99 21 17 61 62 39 40 2 3 11 12 27 26 85 86 91 90 30 31 76 83 7 8 +TICK