Download src/q_route/visualizer.py from jay2219/Q-Route: direct link, hf CLI and curl.
- Browser
- Download file 11.3 kB
-
https://huggingface.co/spaces/jay2219/Q-Route/resolve/main/src/q_route/visualizer.py
- Command line
-
hf download hf://spaces/jay2219/Q-Route/src/q_route/visualizer.py
-
curl -L -o visualizer.py https://huggingface.co/spaces/jay2219/Q-Route/resolve/main/src/q_route/visualizer.py
11.3 kB
| """ | |
| Q-Route Custom Visualization Suite. | |
| Renders three custom visual assets: | |
| 1. Visual 1: Physical QPU Topology Graph with Routing Path Overlay (networkx + matplotlib) | |
| 2. Visual 2: Circuit Diagram Before vs After (Qiskit circuit drawer) | |
| 3. Visual 3: Generation Quality Bar Chart (Plotly graph objects) | |
| """ | |
| import io | |
| from typing import List, Tuple, Dict, Any, Optional | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| import networkx as nx | |
| from PIL import Image | |
| try: | |
| import plotly.graph_objects as go | |
| HAS_PLOTLY = True | |
| except ImportError: | |
| go = None | |
| HAS_PLOTLY = False | |
| try: | |
| import qiskit | |
| from qiskit.visualization import circuit_drawer | |
| from q_route.evaluator import parse_qasm_string, QuantumCircuit | |
| HAS_QISKIT_DRAW = True | |
| except Exception: | |
| HAS_QISKIT_DRAW = False | |
| # Theme Color Definitions | |
| COLOR_BG_DARK = "#0A0A0F" | |
| COLOR_BG_CARD = "#111118" | |
| COLOR_TOPO_EDGE = "#3D4A5C" | |
| COLOR_ROUTE_PATH = "#00D4FF" | |
| COLOR_IMPOSSIBLE = "#FF3D57" | |
| COLOR_NODE_FILL = "#7B2FBE" | |
| COLOR_NODE_BORDER = "#9B4FDE" | |
| COLOR_NODE_TEXT = "#FFFFFF" | |
| COLOR_BAR_SWAPS = "#00D4FF" | |
| COLOR_BAR_DEPTH = "#7B2FBE" | |
| COLOR_BAR_GATES = "#00C853" | |
| COLOR_INVALID_RED = "#FF3D57" | |
| COLOR_GOLD = "#FFD700" | |
| def render_topology_routing_graph( | |
| coupling_map: List[Tuple[int, int]], | |
| requested_gate: Optional[Tuple[int, int]] = None, | |
| routed_path: Optional[List[Tuple[int, int]]] = None, | |
| ) -> plt.Figure: | |
| """ | |
| Render Visual 1: Physical QPU Topology Graph with Routing Path Overlay. | |
| """ | |
| G = nx.Graph() | |
| for u, v in coupling_map: | |
| G.add_edge(u, v) | |
| fig, ax = plt.subplots(figsize=(8, 5), facecolor=COLOR_BG_DARK) | |
| ax.set_facecolor(COLOR_BG_DARK) | |
| # Compute node positions | |
| pos = nx.spring_layout(G, seed=42) if len(G.nodes) > 6 else nx.kamada_kawai_layout(G) | |
| # 1. Base Topology Edges | |
| nx.draw_networkx_edges( | |
| G, pos, ax=ax, edge_color=COLOR_TOPO_EDGE, width=2.5, alpha=0.8 | |
| ) | |
| # 2. Impossible Requested Gate (Red dashed arc) | |
| if requested_gate: | |
| u, v = requested_gate | |
| if u in pos and v in pos: | |
| ax.annotate( | |
| "", | |
| xy=pos[v], | |
| xytext=pos[u], | |
| arrowprops=dict( | |
| arrowstyle="<->", | |
| color=COLOR_IMPOSSIBLE, | |
| linestyle="dashed", | |
| linewidth=2.5, | |
| connectionstyle="arc3,rad=0.35", | |
| ), | |
| ) | |
| mid_x = (pos[u][0] + pos[v][0]) / 2.0 | |
| mid_y = (pos[u][1] + pos[v][1]) / 2.0 + 0.15 | |
| ax.text( | |
| mid_x, | |
| mid_y, | |
| f"REQUESTED: Impossible {u}╌{v}", | |
| color=COLOR_IMPOSSIBLE, | |
| fontsize=9, | |
| fontweight="bold", | |
| ha="center", | |
| backgroundcolor="#0A0A0F80", | |
| ) | |
| # 3. Routed Path (Solid Cyan Overlay) | |
| if routed_path: | |
| path_edges = [] | |
| for i in range(len(routed_path) - 1): | |
| path_edges.append((routed_path[i], routed_path[i + 1])) | |
| nx.draw_networkx_edges( | |
| G, | |
| pos, | |
| edgelist=path_edges, | |
| ax=ax, | |
| edge_color=COLOR_ROUTE_PATH, | |
| width=5.0, | |
| alpha=0.9, | |
| ) | |
| # 4. Nodes | |
| nx.draw_networkx_nodes( | |
| G, | |
| pos, | |
| ax=ax, | |
| node_color=COLOR_NODE_FILL, | |
| edgecolors=COLOR_NODE_BORDER, | |
| linewidths=2.0, | |
| node_size=700, | |
| ) | |
| nx.draw_networkx_labels( | |
| G, | |
| pos, | |
| ax=ax, | |
| font_color=COLOR_NODE_TEXT, | |
| font_weight="bold", | |
| font_size=10, | |
| ) | |
| ax.set_title( | |
| "Visual 1: Physical QPU Topology & Q-Route Solution Overlay", | |
| color="#F0F0FF", | |
| fontsize=12, | |
| fontweight="bold", | |
| pad=12, | |
| ) | |
| ax.axis("off") | |
| plt.tight_layout() | |
| return fig | |
| def render_circuit_before_after( | |
| abstract_qasm: str, routed_qasm: str | |
| ) -> plt.Figure: | |
| """ | |
| Render Visual 2: Qiskit Circuit Diagram Before vs After. | |
| """ | |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4.5), facecolor=COLOR_BG_DARK) | |
| ax1.set_facecolor(COLOR_BG_CARD) | |
| ax2.set_facecolor(COLOR_BG_CARD) | |
| qc_abs = parse_qasm_string(abstract_qasm) if HAS_QISKIT_DRAW else None | |
| qc_rt = parse_qasm_string(routed_qasm) if HAS_QISKIT_DRAW else None | |
| if HAS_QISKIT_DRAW and isinstance(qc_abs, QuantumCircuit) and isinstance(qc_rt, QuantumCircuit): | |
| try: | |
| circuit_drawer(qc_abs, output="mpl", ax=ax1) | |
| circuit_drawer(qc_rt, output="mpl", ax=ax2) | |
| except Exception: | |
| _draw_fallback_text_box(ax1, "BEFORE (Abstract Input)", abstract_qasm, COLOR_IMPOSSIBLE) | |
| _draw_fallback_text_box(ax2, "AFTER (Q-Route Hardware Compliant)", routed_qasm, COLOR_ROUTE_PATH) | |
| else: | |
| _draw_fallback_text_box(ax1, "BEFORE (Abstract Input)", abstract_qasm, COLOR_IMPOSSIBLE) | |
| _draw_fallback_text_box(ax2, "AFTER (Q-Route Hardware Compliant)", routed_qasm, COLOR_ROUTE_PATH) | |
| ax1.set_title("BEFORE (Abstract Input — Illegal Gates)", color=COLOR_IMPOSSIBLE, fontsize=11, fontweight="bold") | |
| ax2.set_title("AFTER (Q-Route Routed — 100% Compliant)", color=COLOR_BAR_GATES, fontsize=11, fontweight="bold") | |
| plt.tight_layout() | |
| return fig | |
| def _draw_fallback_text_box(ax: plt.Axes, title: str, code: str, border_color: str): | |
| ax.axis("off") | |
| code_lines = "\n".join(code.splitlines()[:12]) | |
| ax.text( | |
| 0.05, | |
| 0.90, | |
| f"{title}\n\n{code_lines}", | |
| color="#C8D3E8", | |
| fontsize=8.5, | |
| fontfamily="monospace", | |
| va="top", | |
| bbox=dict(boxstyle="round,pad=0.5", facecolor=COLOR_BG_CARD, edgecolor=border_color, linewidth=1.5), | |
| ) | |
| def render_quality_bar_chart_mpl( | |
| model_eval_metrics: Dict[str, Dict[str, Any]], | |
| theoretical_min_swaps: int = 0, | |
| ) -> plt.Figure: | |
| """Matplotlib fallback rendering engine for Visual 3 Bar Chart.""" | |
| import numpy as np | |
| models = list(model_eval_metrics.keys()) | |
| swaps = [model_eval_metrics[m].get("swap_count", 0) for m in models] | |
| depths = [model_eval_metrics[m].get("depth", 0) for m in models] | |
| gates = [model_eval_metrics[m].get("total_2q_gates", 0) for m in models] | |
| passes = [model_eval_metrics[m].get("pass_topology", False) for m in models] | |
| display_names = [f"{m} ✅" if p else f"{m} ❌ [INVALID]" for m, p in zip(models, passes)] | |
| fig, ax = plt.subplots(figsize=(8.5, max(3.5, len(models) * 0.8)), facecolor=COLOR_BG_DARK) | |
| ax.set_facecolor(COLOR_BG_CARD) | |
| y = np.arange(len(models)) | |
| height = 0.25 | |
| ax.barh(y - height, swaps, height, label="SWAP Gates", color=COLOR_BAR_SWAPS) | |
| ax.barh(y, depths, height, label="Circuit Depth", color=COLOR_BAR_DEPTH) | |
| ax.barh(y + height, gates, height, label="2-Qubit Gates", color=COLOR_BAR_GATES) | |
| if theoretical_min_swaps > 0: | |
| ax.axvline(x=theoretical_min_swaps, color=COLOR_GOLD, linestyle="--", label=f"Min SWAPs ({theoretical_min_swaps})") | |
| ax.set_yticks(y) | |
| ax.set_yticklabels(display_names, color="#F0F0FF", fontsize=9.5) | |
| ax.invert_yaxis() | |
| ax.set_xlabel("Count", color="#A0A0C0", fontsize=10) | |
| ax.set_title("Visual 3: Generation Quality & Topology Compliance Comparison", color="#F0F0FF", fontsize=11, fontweight="bold") | |
| ax.legend(facecolor=COLOR_BG_DARK, edgecolor="#2A2A4A", labelcolor="#F0F0FF", fontsize=8.5) | |
| ax.tick_params(colors="#A0A0C0") | |
| for spine in ax.spines.values(): | |
| spine.set_color("#2A2A4A") | |
| plt.tight_layout() | |
| return fig | |
| def render_quality_bar_chart( | |
| model_eval_metrics: Dict[str, Dict[str, Any]], | |
| theoretical_min_swaps: int = 0, | |
| ) -> Any: | |
| """ | |
| Render Visual 3: Plotly Horizontal Grouped Bar Chart with Matplotlib Fallback. | |
| """ | |
| if not model_eval_metrics: | |
| return None | |
| if HAS_PLOTLY and go: | |
| try: | |
| models = list(model_eval_metrics.keys()) | |
| swaps = [model_eval_metrics[m].get("swap_count", 0) for m in models] | |
| depths = [model_eval_metrics[m].get("depth", 0) for m in models] | |
| gates = [model_eval_metrics[m].get("total_2q_gates", 0) for m in models] | |
| passes = [model_eval_metrics[m].get("pass_topology", False) for m in models] | |
| display_names = [f"{m} ✅" if p else f"{m} ❌ [INVALID]" for m, p in zip(models, passes)] | |
| fig = go.Figure() | |
| fig.add_trace( | |
| go.Bar( | |
| y=display_names, | |
| x=swaps, | |
| name="SWAP Gates", | |
| orientation="h", | |
| marker=dict(color=COLOR_BAR_SWAPS), | |
| text=[f"{s} SWAPs" for s in swaps], | |
| textposition="auto", | |
| ) | |
| ) | |
| fig.add_trace( | |
| go.Bar( | |
| y=display_names, | |
| x=depths, | |
| name="Circuit Depth", | |
| orientation="h", | |
| marker=dict(color=COLOR_BAR_DEPTH), | |
| text=[f"Depth {d}" for d in depths], | |
| textposition="auto", | |
| ) | |
| ) | |
| fig.add_trace( | |
| go.Bar( | |
| y=display_names, | |
| x=gates, | |
| name="2-Qubit Gates", | |
| orientation="h", | |
| marker=dict(color=COLOR_BAR_GATES), | |
| text=[f"{g} Gates" for g in gates], | |
| textposition="auto", | |
| ) | |
| ) | |
| if theoretical_min_swaps > 0: | |
| fig.add_vline( | |
| x=theoretical_min_swaps, | |
| line_dash="dash", | |
| line_color=COLOR_GOLD, | |
| annotation_text=f"Theoretical Min SWAPs ({theoretical_min_swaps})", | |
| annotation_position="top right", | |
| annotation_font_color=COLOR_GOLD, | |
| ) | |
| fig.update_layout( | |
| title=dict( | |
| text="<b>Visual 3: Generation Quality & Topology Compliance Comparison</b>", | |
| font=dict(family="Space Grotesk, sans-serif", size=15, color="#F0F0FF"), | |
| ), | |
| barmode="group", | |
| paper_bgcolor=COLOR_BG_DARK, | |
| plot_bgcolor=COLOR_BG_CARD, | |
| font=dict(family="Inter, sans-serif", color="#A0A0C0"), | |
| xaxis=dict( | |
| title="Count", | |
| gridcolor="#2A2A4A", | |
| showgrid=True, | |
| zerolinecolor="#3D3D6B", | |
| ), | |
| yaxis=dict( | |
| autorange="reversed", | |
| gridcolor="#2A2A4A", | |
| ), | |
| legend=dict( | |
| orientation="h", | |
| yanchor="bottom", | |
| y=1.02, | |
| xanchor="right", | |
| x=1, | |
| font=dict(color="#F0F0FF"), | |
| ), | |
| margin=dict(l=20, r=20, t=60, b=40), | |
| height=380, | |
| ) | |
| return fig | |
| except Exception: | |
| pass | |
| return render_quality_bar_chart_mpl(model_eval_metrics, theoretical_min_swaps) | |