Skip to content

Commit e29fc00

Browse files
committed
Expand problem catalog, add score_summary, polish light/dark UI
- Add 8 classic CO problems: Knapsack, NumberPartitioning, VertexCover, GraphBisection, MaxSAT3, TSP, QAP, NQueens (src/qqa/problems/extras.py), wired through the Python API, CLI (qqa solve --problem ...), and Streamlit builder. - Introduce COProblem.score_summary() and AnnealResult.score so every run reports a human-readable, problem-specific metric (e.g. "IS size: 22", "tour length: 3.28", "clauses satisfied: 48 / 48") with a feasibility flag alongside the raw loss. Overrides for MIS, MaxClique, MaxCut, Coloring, BalancedGraphPartition, Ising / EA / SK, BinaryPerceptron, HopfieldMemory, and the new classical problems. - anneal() now stores the *single* winning replica as best_sol for non-instance problems and runs score_summary on it after training. - Fix BinaryRelaxation.project to clamp before rounding so continuous variables that drifted outside [0,1] yield valid discrete projections. - Streamlit UI: light mode default with a sidebar light / dark toggle, refreshed CSS, Plotly theming helper, score card component, mean ± sigma live loss band, best-so-far-sorted population heatmap, diversity curve, and new Ridgeline / Replica-fate tabs on the Visualize page. - Refresh README problem catalog + GUI description to match. Made-with: Cursor
1 parent 13f1b15 commit e29fc00

66 files changed

Lines changed: 3399 additions & 220 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.streamlit/config.toml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
# paint (before custom CSS kicks in) is already on-brand.
55

66
[theme]
7-
base = "dark"
8-
primaryColor = "#38bdf8"
9-
backgroundColor = "#05060a"
10-
secondaryBackgroundColor = "#0b1120"
11-
textColor = "#e2e8f0"
12-
font = "sans serif"
7+
base = "light"
8+
primaryColor = "#0f766e"
9+
backgroundColor = "#fbfaf6"
10+
secondaryBackgroundColor = "#ffffff"
11+
textColor = "#0f172a"
12+
font = "serif"
1313

1414
[server]
1515
maxUploadSize = 20

README.md

Lines changed: 176 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ PyTorch implementation of the ICLR 2025 paper
44
**[Continuous Tensor Relaxation for Finding Diverse Solutions in Combinatorial Optimization](https://openreview.net/forum?id=9EfBeXaXf0)**
55
by Yuma Ichikawa and Yamato Arai.
66

7+
<p align="center">
8+
<a href="https://colab.research.google.com/github/Yuma-Ichikawa/QQA4CO/blob/main/examples/00_colab_quickstart.ipynb">
9+
<img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open Quickstart in Colab">
10+
</a>
11+
<a href="https://parallelquasiquantum4co.streamlit.app/">
12+
<img src="https://static.streamlit.io/badges/streamlit_badge_black_white.svg" alt="Open in Streamlit">
13+
</a>
14+
</p>
15+
716
<p align="center">
817
<img src="data/fig/demo.gif" width="400">
918
</p>
@@ -72,11 +81,18 @@ print(f"E_0 / N ≈ {result.best_obj / 100:.4f} (target ≈ -0.7632)")
7281
| Category | Classes |
7382
| ----------------- | ------- |
7483
| Binary QUBO | `MaximumIndependentSet`, `MaxClique`, `MaxCut` (+ `*Instance` batched variants) |
84+
| Binary (classic CO) | `Knapsack`, `NumberPartitioning`, `VertexCover`, `GraphBisection`, `MaxSAT3` |
7585
| Categorical | `Coloring`, `BalancedGraphPartition` |
86+
| Categorical (permutation) | `TSP`, `QAP`, `NQueens` |
7687
| 1D Ising | `Ising1D` |
7788
| Spin glass | `EdwardsAnderson`, `SherringtonKirkpatrick` |
7889
| Statistical phys. | `BinaryPerceptron`, `HopfieldMemory` |
7990

91+
Every problem exposes `problem.score_summary(x_disc) -> dict` so the CLI /
92+
GUI can display a human-readable metric (e.g. "IS size: 22", "packed
93+
value: 358", "tour length: 3.28") and a feasibility flag alongside the
94+
raw loss.
95+
8096
Read the full mathematical definitions in
8197
[`docs/problems.md`](docs/problems.md).
8298

@@ -101,15 +117,40 @@ qqa gui
101117

102118
The dashboard has four pages:
103119

104-
- **Home** — pick a problem, size, seed, and problem-specific parameters.
120+
- **Home** — pick a problem family (Graph, Classic CO, Categorical /
121+
permutation, Physics), size, seed, and problem-specific parameters.
105122
- **Solve** — set QQA hyper-parameters and launch a run with a live
106-
progress bar, live metrics, and a streaming loss/best plot powered by a
107-
`StreamlitCallback`.
123+
progress bar, a `mean ± σ` loss band across the parallel replicas, a
124+
population heatmap sorted by best-so-far, a population-diversity curve,
125+
and a headline score card (e.g. "IS size: 22 / 40").
108126
- **Visualize** — tabbed view of dynamics, best trajectory, the applied
109-
annealing schedule, and a solution heatmap.
127+
annealing schedule, a solution heatmap, parallel population, PCA
128+
trajectory, ridgeline of loss distributions, and per-replica fate
129+
lines.
110130
- **Compare** — run a small hyper-parameter grid and inspect the result
111131
with parallel-coordinates and overlaid trajectories.
112132

133+
A light / dark toggle lives in the sidebar; both themes share an
134+
academic, Plotly-aware palette.
135+
136+
### Live demo
137+
138+
A hosted instance runs at
139+
**<https://parallelquasiquantum4co.streamlit.app/>**. The operator runbook,
140+
including how to switch the Streamlit Community Cloud app from *Private* to
141+
*Anyone with the link*, is in
142+
[`deploy/STREAMLIT_DEPLOY.md`](deploy/STREAMLIT_DEPLOY.md). A quick health
143+
check is available via:
144+
145+
```bash
146+
uv run python scripts/check_streamlit_deploy.py
147+
```
148+
149+
> **Note.** If the URL currently redirects to `/-/auth/app?…`, the app is
150+
> still set to Private on Streamlit Community Cloud. The fix is a single
151+
> setting in the Streamlit Cloud dashboard — see
152+
> [`deploy/STREAMLIT_DEPLOY.md §1`](deploy/STREAMLIT_DEPLOY.md#1-why-is-the-url-redirecting-to--auth-app).
153+
113154
## Deploy to the public web (free)
114155

115156
The dashboard can be published for free via **Streamlit Community Cloud**
@@ -180,10 +221,140 @@ Every function accepts `backend="matplotlib"` (default) or `backend="plotly"`.
180221
Plotly is optional; if it is not installed the plot silently falls back to
181222
matplotlib.
182223

224+
### Visualization gallery
225+
226+
All figures below are produced by `scripts/make_gallery.py` (regenerate with
227+
`uv run python scripts/make_gallery.py`) and stored under
228+
[`data/fig/gallery/`](data/fig/gallery). Each row shows one problem family
229+
from the catalog; the columns are, left → right, **dynamics**
230+
(`plot_history`), **best trajectory** (`plot_best_trajectory`), **best
231+
solution heatmap** (`plot_solution_heatmap`), and **parallel-population**
232+
evolution (`plot_population_evolution`).
233+
234+
#### Default annealing schedule
235+
236+
<p align="center">
237+
<img src="data/fig/gallery/schedule_default.png" width="520" alt="Default linear bg schedule from -3.0 to +0.1">
238+
</p>
239+
240+
#### Maximum Independent Set (N=40, 3-regular)
241+
242+
<p align="center">
243+
<img src="data/fig/gallery/history_mis.png" width="900" alt="MIS loss/penalty/diversity dynamics">
244+
</p>
245+
<p align="center">
246+
<img src="data/fig/gallery/best_mis.png" width="440">
247+
<img src="data/fig/gallery/solution_mis.png" width="440">
248+
<img src="data/fig/gallery/population_mis.png" width="440">
249+
</p>
250+
251+
#### Max-Cut (Erdős–Rényi, N=40, p=0.15)
252+
253+
<p align="center">
254+
<img src="data/fig/gallery/history_maxcut.png" width="900">
255+
</p>
256+
<p align="center">
257+
<img src="data/fig/gallery/best_maxcut.png" width="440">
258+
<img src="data/fig/gallery/solution_maxcut.png" width="440">
259+
<img src="data/fig/gallery/population_maxcut.png" width="440">
260+
</p>
261+
262+
#### Graph coloring (N=30, 4-regular, K=3)
263+
264+
<p align="center">
265+
<img src="data/fig/gallery/history_coloring.png" width="900">
266+
</p>
267+
<p align="center">
268+
<img src="data/fig/gallery/best_coloring.png" width="440">
269+
<img src="data/fig/gallery/population_coloring.png" width="440">
270+
</p>
271+
272+
#### Ising 1D ferromagnet (N=32, J=1, periodic)
273+
274+
<p align="center">
275+
<img src="data/fig/gallery/history_ising1d.png" width="900">
276+
</p>
277+
<p align="center">
278+
<img src="data/fig/gallery/best_ising1d.png" width="440">
279+
<img src="data/fig/gallery/solution_ising1d.png" width="440">
280+
<img src="data/fig/gallery/population_ising1d.png" width="440">
281+
</p>
282+
283+
#### Edwards–Anderson 3D spin glass (L=4, seed=0)
284+
285+
<p align="center">
286+
<img src="data/fig/gallery/history_ea3d.png" width="900">
287+
</p>
288+
<p align="center">
289+
<img src="data/fig/gallery/best_ea3d.png" width="440">
290+
<img src="data/fig/gallery/solution_ea3d.png" width="440">
291+
<img src="data/fig/gallery/population_ea3d.png" width="440">
292+
</p>
293+
294+
#### Sherrington–Kirkpatrick mean-field spin glass (N=80)
295+
296+
<p align="center">
297+
<img src="data/fig/gallery/history_sk.png" width="900">
298+
</p>
299+
<p align="center">
300+
<img src="data/fig/gallery/best_sk.png" width="440">
301+
<img src="data/fig/gallery/solution_sk.png" width="440">
302+
<img src="data/fig/gallery/population_sk.png" width="440">
303+
</p>
304+
305+
#### Binary perceptron (N=40, α=0.4)
306+
307+
<p align="center">
308+
<img src="data/fig/gallery/history_perceptron.png" width="900">
309+
</p>
310+
<p align="center">
311+
<img src="data/fig/gallery/best_perceptron.png" width="440">
312+
<img src="data/fig/gallery/solution_perceptron.png" width="440">
313+
<img src="data/fig/gallery/population_perceptron.png" width="440">
314+
</p>
315+
316+
#### Hopfield memory (N=64, P=3)
317+
318+
<p align="center">
319+
<img src="data/fig/gallery/history_hopfield.png" width="900">
320+
</p>
321+
<p align="center">
322+
<img src="data/fig/gallery/best_hopfield.png" width="440">
323+
<img src="data/fig/gallery/solution_hopfield.png" width="440">
324+
<img src="data/fig/gallery/population_hopfield.png" width="440">
325+
</p>
326+
327+
## Verified correctness
328+
329+
We run QQA against a ground truth or a strong baseline for every problem in
330+
the catalog via `scripts/verify_all_problems.py`. The most recent sweep
331+
(29 instances across 9 problem families) is stored in
332+
[`tasks/verification_report.md`](tasks/verification_report.md); headline
333+
numbers:
334+
335+
| Problem | Instances | Reference | QQA |
336+
| --- | --- | --- | --- |
337+
| Maximum Independent Set | 3×(3-reg, N=50) | networkx degree-greedy | **matches or beats greedy on all seeds** |
338+
| MaxCut | 3×ER (N=30/40/60) | best-of-400 random partition | **+6 / +16 / +27 edges over random** |
339+
| MaxClique | 3×ER (N=30/40/50) | nx.approximation.max_clique | **+1 vertex on every seed** |
340+
| Graph coloring (K=3) | 3×(3-reg, N=40) | Welsh–Powell greedy | **0 conflicts on all seeds** |
341+
| Ising 1D ferromagnet | N ∈ {16, 32, 64} | exact E₀ = −N | **gap = 0 on every size** |
342+
| Edwards–Anderson 2D L=3 | 3 seeds | brute force (2⁹) | **matches exact ground state** |
343+
| Edwards–Anderson 3D L=4 | 2 seeds || E/N ≈ −1.61 (no exact solver) |
344+
| Sherrington–Kirkpatrick | N ∈ {50, 100, 200} | Parisi e₀ = −0.7632 | **≤ 3.2 % gap at N=200** |
345+
| Binary perceptron | α ∈ {0.3, 0.5, 0.7} | teacher reaches 0 errors | **0 errors on all α** |
346+
| Hopfield memory | (N, P) ∈ {(32,2),(64,3),(128,4)} | ≥ 0.95 overlap | **overlap = 1.0** |
347+
348+
Overall: **29 / 29 checks pass (100 %)**. Re-run with
349+
`uv run python scripts/verify_all_problems.py`; the command regenerates the
350+
Markdown report in place.
351+
183352
## Notebooks
184353

185-
Eight runnable notebooks live in [`examples/`](examples/):
354+
Nine runnable notebooks live in [`examples/`](examples/). Each notebook has
355+
an **Open in Colab** badge in its first cell and auto-installs `qqa` on Colab.
186356

357+
0. `00_colab_quickstart.ipynb` — one-click tour of every problem
187358
1. `01_maximum_independent_set.ipynb`
188359
2. `02_graph_coloring.ipynb`
189360
3. `03_max_cut.ipynb`

0 commit comments

Comments
 (0)