# L4 Solution — GAP-TV on CASSI KAIST 10-Scene

**ID:** `PWM-L4-cassi-kaist-gaptv`
**Parent Principle:** [`PWM-L1-em-maxwell-vacuum`](../principle/principle.md)
**Parent Spec:** [`PWM-L2-em-cassi-forward`](../spec/spec.md)
**Parent Benchmark:** [`PWM-L3-cassi-kaist-10scenes`](../benchmark/benchmark.md)
**Status:** ⊙ Testnet (genesis)
**Submitter:** _(wallet address)_

---

## 1. AI System / Algorithm

**Generalized Alternating Projection with Total Variation regularization (GAP-TV)** — a classical optimization-based solver (no neural network, no training data). GAP-TV alternates between (a) a data-fidelity projection that enforces `Φ x = y` and (b) a TV-prior denoising step that enforces spatial-spectral smoothness.

```
x_{k+1} = D_λ ( x_k + Φ^T (y - Φ x_k) / ||Φ||² )
```

where `D_λ` is the band-by-band TV-denoising operator (Chambolle, 2004) and `λ` is annealed from 1.0 to 0.05 over 200 iterations.

This is the **reference genesis baseline**. Submitting a strictly-better solver displaces this from the leaderboard.

## 2. Reconstruction Approach

| Step | Description |
|------|-------------|
| Init | `x_0 = Φ^T y` (back-projection) |
| Loop | For k = 1..200: enforce data fidelity, then denoise each band with TV |
| Halt | When `||x_{k+1} − x_k||_2 / ||x_k||_2 < 1e-4` or k = 200 |
| Output | Final cube `x̂` clipped to [0, 1] |

GPU: a single A100 finishes all 10 scenes in ~12 seconds. CPU fallback (NumPy + SciPy) takes ~90 seconds per scene.

## 3. Self-Reported Performance

Measured on the held-out 10-scene set with `sigma = 0.01` and `seed = 42`:

| Metric | Threshold | Achieved | Pass? |
|--------|-----------|----------|-------|
| PSNR (dB) | ≥ 28.0 | **32.4** | ✅ |
| SSIM | ≥ 0.85 | **0.881** | ✅ |
| SAM (rad) | ≤ 0.20 | **0.142** | ✅ |

Per-scene breakdown available in [`reports/results.md`](./reports/results.md). Reproduction instructions in [`reports/reproduce.md`](./reports/reproduce.md).

## 4. Resources

- **Code entry point:** [`code/solver.py`](./code/solver.py) — `def solve(y, mask, dispersion, sigma) -> x_hat`
- **Dependencies:** [`code/requirements.txt`](./code/requirements.txt)
- **Container:** `ghcr.io/pwm-protocol/cassi-gaptv:0.1.0`
- **Compute cost:** ~$0.02 per scene at A100 spot prices (Nov 2025).

## 5. Limitations

- Pure TV prior over-smooths fine spectral textures — neural priors (e.g. MST-L, DGSMP) score 2–4 dB higher.
- Sensitive to dispersion misalignment > 0.5 px.
- Does **not** generalize to grayscale masks or doubly-dispersive CASSI — those need a sibling spec.

## 6. References

- Yuan, X. "Generalized Alternating Projection Based Total Variation Minimization for Compressive Sensing." *ICIP* 2016.
- Chambolle, A. "An Algorithm for Total Variation Minimization and Applications." *J. Math. Imaging Vis.* 20, 89–97 (2004).

---

## File Mapping

| File | Role | How to regenerate |
|------|------|-------------------|
| `solution.md` | Source of truth | Human or LLM |
| `solution.json` | Structured metadata | LLM regenerates from §1 Algorithm, §2 Approach, §3 Self-Reported Performance, §4 Resources |
| `code/solver.py` | Reference implementation | LLM generates from §1 Algorithm + §2 Approach. Must expose `solve(y, mask, dispersion, sigma) -> x_hat` |
| `code/requirements.txt` | Python dependencies | LLM lists exact packages used in `solver.py` |
| `reports/results.md` | Per-scene metric breakdown | **Generated by running** `python code/solver.py --benchmark PWM-L3-cassi-kaist-10scenes --report` |
| `reports/reproduce.md` | How a third party verifies the claim | LLM regenerates as a step-by-step recipe matching what was actually run |
| `reports/figures/` | PNG visualizations of reconstructed cubes | Produced by the reproduction run |

**Prompt for your LLM after editing `solution.md`:**

> Read `solution.md`. Regenerate the bundle:
> 1. `solution.json` with schema: `{ id, principle_id, spec_id, benchmark_id, name, algorithm, algorithm_class: "optimization"|"neural"|"hybrid", description, code_entry, container_image, self_reported_metrics: [{metric, value, unit}], resources: {gpu_hours, dollar_cost, dependencies[]}, limitations[], references[] }`
> 2. `code/solver.py` exposing `solve(y, mask, dispersion, sigma) -> x_hat` and matching the algorithm in §1 and §2.
> 3. `code/requirements.txt` with the exact packages used.
> 4. `reports/reproduce.md` with step-by-step verification instructions.
>
> Output each file in its own fenced block tagged with the filename so I can save them.
> Do **not** fabricate `reports/results.md` numbers — those must come from actually running the solver.
