Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 115 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,131 @@

# ClusterSim

A cluster state simulator for measurement-based quantum computation, in browser. Try it here: [https://clustersim.app](https://clustersim.app)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python Version](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/)

**ClusterSim** is an interactive, browser-based simulator for measurement-based quantum computation (MBQC) and stabilizer circuits using a graph state representation.

> Based on the paper 'Fast simulation of stabilizer circuits using a graph state representation' by Simon Anders and Hans J. Briegel ([here](https://arxiv.org/abs/quant-ph/0504117v2))
Live Web Application: [https://clustersim.app](https://clustersim.app)

> Based on the paper *"Fast simulation of stabilizer circuits using a graph state representation"* by Simon Anders and Hans J. Briegel ([arXiv:quant-ph/0504117v2](https://arxiv.org/abs/quant-ph/0504117v2)).

---

## Key Features

- **Interactive 2D Cytoscape Interface (`graph2d_app.py`)**:
- **Quantum Gate Application**: Apply Pauli gates ($X$, $Y$, $Z$), Clifford gates ($H$, $S$, $S^\dagger$), Controlled operations ($CX$, $CZ$), and Local Complementations ($LC$, $LCR$).
- **Measurements**: Measure qubits in $X$, $Y$, or $Z$ bases with random or forced outcomes ($0$ or $1$).
- **Fusion Gates**: Execute 2-qubit fusion gates ($XXZZ$, $XZZX$, $XYYZ$) with success/failure modes and outcome control.
- **Graph Manipulations**: Add/remove nodes, toggle/delete edges, and copy/duplicate subgraphs.
- **Compound Group Containers**: Hierarchically group and ungroup selected qubits into parent container boxes.
- **Snapshot-Based Undo / Redo**: Step backward and forward through any sequence of quantum operations or plot customizations.
- **Move Log & String Export**: Track step-by-step move history and load/export graph state string representations.
- **Styling & Export Options**: Customize node labels, preset Cytoscape shapes, snap nodes to a grid, and export to SVG or JSON.

- **3D Grid Visualization (`grid3d_app.py`)**:
- Interactive 3D lattice cluster state simulation and visualization.

## Installation

To install, use:
### Prerequisites

- Python `>= 3.12`
- [`uv`](https://github.com/astral-sh/uv) (recommended) or standard `pip`

### Install from Source

```bash
git clone https://github.com/zhiihan/ClusterSim.git
cd ClusterSim

# Using pip:
pip install -e .

# Or using uv:
uv sync
```

---

## Quick Start

### 1. Launch the 2D Graph Simulator

```bash
python graph2d_app.py
```

Open your browser and navigate to `http://127.0.0.1:8050/`.

#### Keyboard Shortcuts (2D App)
- **$N$**: Add node
- **$E$**: Toggle edge between selected nodes
- **Shift + $E$**: Delete edge between selected nodes
- **Backspace**: Delete selected node(s)
- **$H$**: Apply Hadamard ($H$) gate
- **$W$**: Apply Local Complementation ($LC$)
- **$G$**: Group / Ungroup selected nodes
- **Ctrl + $C$ / Ctrl + $V$**: Copy and paste/duplicate selected nodes
- **Ctrl + $Z$ / Ctrl + $Y$**: Undo / Redo

### 2. Launch the 3D Grid Simulator

```bash
python grid3d_app.py
```

Open your browser and navigate to `http://127.0.0.1:8050/`.

---

## Project Structure

`pip install .`
```text
ClusterSim/
├── assets/ # Static assets and clientside JS listeners
├── src/
│ └── clustersim/
│ └── simulator/
│ ├── cluster_state.py # Core ClusterState stabilizer simulation engine
│ └── frontend_cluster_state.py # 2D layout adapter (metadata, groups, undo stack)
│ └── components/
│ ├── components_2d/ # Dash 2D UI components (action panel, Cytoscape, figure)
│ └── components_3d/ # Dash 3D UI components
├── tests/ # Pytest test suite
├── graph2d_app.py # 2D Dash Application Entry Point
├── grid3d_app.py # 3D Dash Application Entry Point
├── pyproject.toml # Project configuration & dependencies
└── README.md # Documentation
```

---

After installation, run
## Testing & Quality

Run the test suite using `pytest`:

```bash
pytest
```
python grid3dfigure.py

Run code formatting checks with `ruff`:

```bash
ruff format --check
```

---

## References

1. S. Anders, H. J. Briegel, *"Fast simulation of stabilizer circuits using a graph state representation"*, [Phys. Rev. A 73, 022334 (2006)](https://arxiv.org/abs/quant-ph/0504117v2).
2. M. Hein, J. Eisert, H. J. Briegel, *"Multi-party entanglement in graph states"*, [Phys. Rev. A 69, 062311 (2004)](https://arxiv.org/abs/quant-ph/0307130).
3. D. Schlingemann, *"Cluster states, graph states, and stabilizer codes"*, [quant-ph/0111080](https://arxiv.org/abs/quant-ph/0111080).

---

### Graph State
## License

* This implementation is based around graph states.
These were introduced in the paper about entanglement purification ([here](https://arxiv.org/abs/quant-ph/0512218)) to study the entanglement properties of certain multi-qubit systems
* Takes their name from graphs in maths
* Each qubit corresponds to a vertex of the graph, and each edge indicates which qubits have interacted.
* There is a bijection between stabilizer states (the states that can appear in a stabilizer circuit) and graph states. That is, every graph state has a corresponding stabilizer state, and every stabilizer state has a corresponding graph state.
* This can be shown as: Any stabilizer state can be transformed to a graph state by applying a tensor product of local Clifford operations. These are known as *vertex operators* (VOPs). See [this paper](https://arxiv.org/abs/quant-ph/0111080) and [this paper](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.69.022316).
* The standard approach is to store a tableau of stabillzer operators (an $n \times n$ matrix of Pauli operators).
* The improved algorithm needs only the graph state and the list of VOPs, and requires space $\mathcal{O}(n \log n)$.
* To then change the state, measurement is studied in [this paper](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.69.062311), and gate application in [the paper mentioned above](https://arxiv.org/pdf/quant-ph/0504117v2.pdf).
This project is licensed under the [MIT License](LICENSE).
13 changes: 13 additions & 0 deletions assets/clientside.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
window.dash_clientside = window.dash_clientside || {};
window.dash_clientside.clientside = {
keydown_listener: function (dummy) {
if (window._keydown_listener_attached) {
return window.dash_clientside.no_update;
}
window._keydown_listener_attached = true;

document.addEventListener('keydown', function (e) {
// Do not capture keys if the user is typing in an input or textarea
const active = document.activeElement;
Expand Down Expand Up @@ -87,6 +92,14 @@ window.dash_clientside.clientside = {
btn.click();
}
}
// Check if G (Group / Ungroup)
if (!e.ctrlKey && !e.metaKey && !e.shiftKey && (e.key === 'g' || e.key === 'G')) {
const btn = document.getElementById('key-g-btn');
if (btn) {
e.preventDefault();
btn.click();
}
}
}, true);
return window.dash_clientside.no_update;
}
Expand Down
64 changes: 60 additions & 4 deletions assets/custom_style.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ body {
/* Fullscreen cytoscape container positioned below the top panel */
.cytoscape-container {
position: absolute;
top: 194px;
/* 12px top + 170px panel + 12px gap */
top: 114px;
/* 12px top + 90px panel + 12px gap */
left: 16px;
right: 16px;
bottom: 16px;
Expand All @@ -40,7 +40,8 @@ body {
top: 12px;
left: 16px;
right: 16px;
height: 170px;
min-height: 90px;
height: auto !important;
/* Compact height that fully displays controls without clipping */
z-index: 10;
background: rgba(255, 255, 255, 0.96) !important;
Expand All @@ -49,7 +50,7 @@ body {
border: 1px solid #dee2e6 !important;
border-radius: 12px !important;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
padding: 12px 20px;
padding: 6px 20px;
overflow: visible;
/* Allows dropdown menus to float over the canvas */
}
Expand Down Expand Up @@ -94,4 +95,59 @@ pre {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 13px;
color: #212529;
}

/* Responsive Toolbar for Mobile */
@media (max-width: 1199px) {
.glass-top-panel {
height: auto !important;
min-height: 90px;
padding: 8px 16px !important;
}
.scrollable-toolbar-container {
overflow-x: auto;
overflow-y: hidden;
width: 100%;
scrollbar-width: none; /* Firefox */
}
.scrollable-toolbar-container::-webkit-scrollbar {
display: none; /* Chrome, Safari, Opera */
}
.scrollable-toolbar-container .row {
display: flex !important;
flex-wrap: nowrap !important;
width: max-content !important;
}
.scrollable-toolbar-container .btn-group {
flex-wrap: nowrap !important;
}
}

@media (max-width: 767px) {
.glass-top-panel h2 {
font-size: 14px !important;
}
.glass-top-panel #ui {
font-size: 0.65rem !important;
padding: 1px 4px !important;
}
}

/* Floating Rounded-Rectangle Offcanvas Sidebar */
.offcanvas {
top: 12px !important;
bottom: 12px !important;
right: 16px !important;
height: calc(100vh - 24px) !important;
border-radius: 12px !important;
border: 1px solid #dee2e6 !important;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
background: rgba(255, 255, 255, 0.98) !important;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}

/* Ensure modal containers share the same 12px border radius */
.modal-content {
border-radius: 12px !important;
}
4 changes: 3 additions & 1 deletion graph2d_app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from dash import Dash, html, dcc, Input, Output, ClientsideFunction

from components.components_2d import tab_ui_2d, figure_2d
from components.components_2d import tab_ui_2d, figure_2d, cytoscape_offcanvas
from clustersim.app import BrowserState
from clustersim.simulator import ClusterState

Expand All @@ -27,6 +27,7 @@
],
className="app-container",
),
cytoscape_offcanvas,
dcc.Store(id="browser-data"),
dcc.Store(id="graph-data"),
dcc.Store(id="draw-plot"), # This is a dummy variable
Expand All @@ -42,6 +43,7 @@
html.Button(id="key-shift-e-btn", style={"display": "none"}),
html.Button(id="key-h-btn", style={"display": "none"}),
html.Button(id="key-w-btn", style={"display": "none"}),
html.Button(id="key-g-btn", style={"display": "none"}),
html.Div(
id="none",
children=[],
Expand Down
3 changes: 2 additions & 1 deletion src/clustersim/simulator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .cluster_state import ClusterState
from .frontend_cluster_state import FrontendClusterState

__all__ = ["ClusterState"]
__all__ = ["ClusterState", "FrontendClusterState"]
3 changes: 0 additions & 3 deletions src/clustersim/simulator/cluster_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,6 @@ def _parse_ops_from_string(string: str) -> list[tuple[str, list[int], str | None

full_text = " ".join(lines)

if not full_text:
raise ValueError("Cannot construct ClusterState from empty text.")

parsed_ops = []

# Regex to find commands: NAME followed optionally by [numbers]
Expand Down
Loading
Loading