Commit 2b7dbc7
feat(photonlayer): optical simulation core — field, FFT, propagation, detector, receipts (ADR-260 Phase 1) (#587)
* feat(photonlayer): optical simulation core — field, FFT, propagation, detector, receipts (ADR-260 Phase 1)
Pure-Rust, dependency-light, deterministic learned-optical-frontend core:
- complex/fft: in-house radix-2 2D FFT (bit-reproducible, no external FFT lib)
- field/mask: image->scalar field, phase-only learned mask (identity/random/lens)
- propagate: Fresnel, Fraunhofer, angular-spectrum scalar diffraction
- detector: intensity capture + seeded shot/read noise, binning, quantization
- metrics: MSE/PSNR, compression ratio, frame-similarity, spectrum embedding
- receipt: BLAKE3-bound experiment receipts + verify (determinism invariant §21)
21 unit tests + doctest passing.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* feat(photonlayer): in-Rust mask learner, decoder, and benchmark harness (ADR-260 Phase 2/4)
- synthetic: deterministic 4-class shape dataset (no MNIST per ADR-260 §20.2)
- decoder: feature pooling + nearest-centroid digital backend (exact param count)
- learn: seeded block hill-climbing mask optimizer against task loss; learned
mask provably dominates its random start (acceptance gate §17.2)
- baselines: digital/random/learned variants + compression showcase
- Result: at a 2x2 (4-pixel) sensor, learned mask 1.00 vs random 0.80 vs
digital 0.65 test accuracy — same task, 64x fewer sensor pixels (§16.3)
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* chore(photonlayer): scaffold ruvector/cli/wasm crates for swarm implementation (ADR-260)
Stub crates registered as workspace members so each is independently
buildable/testable while the implementation swarm fills them in.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* feat(photonlayer): experiment memory, WASM playback, verification/privacy, CLI demos (ADR-260 Phases 2-4)
photonlayer-ruvector (22 tests): 32-dim experiment embeddings (mask histogram +
frame spectrum), cosine nearest-experiment recall, Fiedler-spectral pass/fail
boundary analysis, mask-family coherence gates, verifying receipt store.
photonlayer-wasm (17 tests): 5-view browser pipeline (incoming/mask/masked/
sensor + frame hash) with min-max u8 encoders; in-browser verify_receipt_json
(anti-swap); default_config_json.
photonlayer-bench (9 tests): + verification module (FAR/FRR/EER) and privacy
module (linear reconstruction-attack leakage). Learned mask EER 0.001 vs random
0.133; optical capture reduces reconstruction PSNR vs identity.
photonlayer-cli: bench / barcode / edge / privacy-gate / verify-receipt demos
with ASCII frame rendering. Barcode decodes all 4 classes from non-human-readable
frames; privacy-gate emits a verifying RVF receipt. Clean build, zero warnings.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* harden(photonlayer): validate untrusted optical configs at the boundary (ADR-260 security)
Add OpticalConfig::validate() + MAX_GRID_DIM cap as the security choke point:
reject non-power-of-two/oversized grids, non-finite or non-physical optical
params, and binning=0 before any allocation or FFT. Enforced in OpticalField::
from_image (pre-allocation) and in the WASM run_trace boundary (dimension guard
+ config.validate) to block allocation-DoS and 32-bit usize overflow from a
malicious config_json. +2 core tests (now 23).
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* docs(photonlayer): ADR-260 — learned-optical-frontend computing simulator
Formalizes the architecture, pipeline, crate layout, RuVector experiment-memory
schema, RVF receipt binding, benchmarks, acceptance gates, the determinism
invariant, and the application/positioning/ethics framing (front-end thesis;
industrial sensors -> drone preprocessing -> medical research -> consented
verification; non-goal: mass-surveillance face ID).
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* docs(photonlayer): ADR-261 (mask exchange + determinism), ADR-262 (privacy verification), SOTA research brief
ADR-261: canonical PhaseMask exchange format, determinism invariant (in-house
FFT + seeded RNG + BLAKE3), and import replay-verification.
ADR-262: privacy-preserving consented verification — FAR/FRR/EER, reconstruction-
attack leakage metric, receipt provenance, RuVector governance; documents the
measured numbers (learned EER 0.001 vs 0.133; optical reduces reconstruction PSNR)
and the mass-surveillance non-goal.
sota.md: D2NN, differentiable optics (TorchOptics/waveprop/diffractsim), hybrid
DOE+CNN compression, edge-enhanced D2NN, 2026 full-Stokes metasurface+U-Net;
credible-vs-overclaimed table; reference->component mapping; feasibility ranking.
Co-Authored-By: claude-flow <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01PjRKJMFe6yoNY3SMVEieHy
* docs+bench(photonlayer): README, assessment/roadmap, more-data benchmark; fix wasm lint
- README (crate/repo face): positioning ("captures the answer"), the auditable
optical-compression wedge, measured compression-sweep table, honest "do not
claim yet" scope.
- docs/research/photonlayer/ASSESSMENT.md: full positioning, use-case risk table,
prove-next roadmap (energy model, harder datasets, reconstruction-attack suite,
hardware bridge), demos, products, scoring, acceptance test, references.
- tests/more_data_bench.rs: larger-N compression sweep (1/4/9/16-px sensors,
40 samples/class, 300 iters) + WIN regression guard. Measured: at 64x reduction
learned=0.988 vs random=0.738.
- Fix photonlayer-wasm useless-comparison lint -> meaningful monotonicity check.
* perf(photonlayer): M1 — cached + in-place Propagator (1.70x, bit-identical)
Hot-path optimization for the mask-learning loop, which propagates thousands
of fields through one fixed config. The config-only transfer function H was
recomputed on every call, and every propagate() cloned the field buffer.
- Propagator precomputes H once per (config,w,h); propagate_into() runs the
forward FFT -> xH -> inverse FFT in place (no per-call clone).
- Output is bit-for-bit identical to the free propagate() (asserted in
cached_propagator_is_bit_identical, always-on).
- Measured 1.70x over the naive path at 64x64 x3000 (release):
naive=615ms -> cached+inplace=361ms. Proof is an --ignored timing test
(debug wall-clock is meaningless); correctness gate runs in the default suite.
Also lands:
- ADR-263 PhotonLayer FiberGate (transmission-matrix MMF backend; receipt-
verified, NOT zero-knowledge; non-square T; nalgebra column-major contract).
- docs/research/photonlayer/APPLICATIONS.md — task-trained-sensors positioning,
application areas, viral demos, product path, platform acceptance test.
Co-Authored-By: claude-flow <ruv@ruv.net>
* feat(photonlayer): real-data MNIST optical-compression benchmark + differential ablation (M2)
Adds an honest, reproducible real-data benchmark for the learned optical
frontend (ADR-260 M2), replacing the synthetic-only 4-class evaluation that
ADR-260 itself flagged as a scientific-integrity risk.
New modules (photonlayer-bench):
- mnist.rs : parses raw uncompressed IDX (verified magic 0x803/0x801),
downsamples 28x28 -> 20x20 centered in a 32x32 power-of-two
optical grid. Dataset is fetched once into a gitignored cache
(NOT vendored); loader has zero network/decompression deps.
- diffdetect.rs: differential-detection readout (Li/Ozcan arXiv:1906.03417) -
10 positive + 10 negative detector regions, score I+_k - I-_k.
- mnist_bench.rs: trains one phase mask (seeded block hill-climbing) and runs
the full acceptance comparison + ablation on the IDENTICAL mask.
Integration test (mnist_differential_bench.rs, NOT a standalone bin to avoid
the CrowdStrike AV os-error-5 on fresh exes): fast always-on smoke guard +
#[ignore] heavy run with a documented command.
Measured (deterministic, seed 0x6e157, 4000 train / 2000 blind test, balanced):
full-image baseline (1024 px, 10240-param centroid) 0.7540
optical compressed ( 64 px, 640-param centroid) 0.7420
delta vs baseline -0.0120 (PASS, allows -0.02)
sensor pixel reduction 16.0x (>= 16x)
digital MAC reduction 16.0x (>= 10x)
learned vs random mask (decoded) +0.0925
ACCEPTANCE (user's relative-to-baseline test): PASS.
Honest caveats reported in-table: this is a SINGLE hill-climbed phase mask +
tiny decoder (single-layer optical compression). The Li/Ozcan ~97% MNIST figure
is a 5-layer diffractive net trained end-to-end by backprop with differential
readout as the final layer; multi-layer + gradient is future work. The
optics-only argmax differential lever is reported as a transparency floor (the
mask is trained for the decoder readout, not the argmax readout). No absolute
SOTA claim is made.
cargo test -p photonlayer-core (23 pass) and -p photonlayer-bench --lib
(14 pass) green; clippy clean.
Co-Authored-By: claude-flow <ruv@ruv.net>
* docs(photonlayer): M3 — fold verified MNIST result + honest positioning + citations into ASSESSMENT
Adds the measured real-data MNIST table (optical 74.20% vs full-image baseline
75.40%, -1.20pp, 16x sensor + 16x MAC reduction; +9.25pp learned-vs-random),
the verbatim non-overclaiming positioning paragraph (competitive single-layer
optical compression, NOT a new accuracy SOTA), the must-avoid language list,
and the closest architectural citations (Wirth-Singh arXiv:2406.06534 primary,
Bezzam 2206.01429, Lin Science 2018, Li/Ozcan 1906.03417, Wang 2507.17374).
Co-Authored-By: claude-flow <ruv@ruv.net>
* perf(photonlayer-core): fold Fraunhofer fftshift into checkerboard premult + precompute FFT twiddle tables
OPT-A (bit-identical): replace `fft_2d + fftshift_2d` in both Fraunhofer
paths (free `fraunhofer()` and `Propagator::propagate_into`) with a ±1
checkerboard premultiply `(-1)^(x+y)` before the transform. By the DFT
shift theorem, FFT of the premultiplied input equals fftshift of the FFT,
eliminating the fftshift's full-buffer alloc + quadrant copy. True negate
(`Complex::ZERO - c`) is exact ±1.0 -> element-for-element identical to the
old sequence (new test `checkerboard_premult_equals_fft_then_fftshift`).
OPT-B (deliberately changes bits, determinism gain): precompute a per-
dimension `TwiddleTable` (`exp(sign·2π·j/n)` for j in 0..n/2) and INDEX it
by stride per butterfly instead of accumulating `w *= wlen`. Kills the f32
drift the accumulation injected and recomputes angles once per 2D FFT
instead of per row/column. Proven: FFT is bit-for-bit reproducible across
runs, and max-abs error vs an f64 reference DFT does NOT increase
(it decreases — drift removed). No hardcoded golden hashes/values in the
repo to update; re-run-determinism tests stay valid by construction.
Measured (release, 64x64 x3000, --ignored --nocapture):
fraunhofer OPT-A+B: old(fft+fftshift,accum-twiddle)=210.5ms ->
new(checkerboard+table)=116.1ms = 1.81x, max_diff_vs_old=5.7e-6 (f32 noise).
M1 cached-propagator benchmark still 2.00x and bit-identical.
All 27 photonlayer-core unit tests + propagation bit-identical gate green;
photonlayer-ruvector / photonlayer-bench / photonlayer-cli build and tests
green. Determinism invariant preserved (scalar cos/sin FFT, no FMA/SIMD/RFFT).
Co-Authored-By: claude-flow <ruv@ruv.net>
* feat(photonlayer): add Config B (argmax-diff-trained mask) to MNIST bench — isolates the differential lever
The M2 benchmark previously reported the differential-vs-plain argmax delta as a
small (+0.10pp) transparency footnote, because the single mask was trained for
the DECODER objective, not the argmax readout. That understated the Li/Ozcan
differential-detection mechanism. This adds a SECOND, clearly-labeled mask
trained directly for the argmax-differential objective, so the lever is shown in
isolation. Config A is unchanged and remains the product/acceptance headline.
Two masks, two objectives — A proves task-useful compression (the product
claim); B isolates the differential-detection lever (the mechanism). Both fully
deterministic (stated seeds), both reproduced by the integration test.
Measured (real MNIST, 4000 train / 2000 blind test, on current core HEAD):
CONFIG A (decoder objective, seed 0x6e157) — product/acceptance:
full-image baseline (1024 px) 0.7540
optical compressed ( 64 px) 0.7305 (-2.35pp; 16x sensor + 16x MACs)
learned vs random decoded +0.0810 (WIN guard, asserted)
CONFIG B (argmax-diff objective, seed 0x6e15c) — mechanism, NO decoder:
plain argmax I+_k 0.1840
differential argmax I+ - I- 0.3490
differential lever delta +0.1650 (asserted >= +0.05)
NOTE: absolute accuracy is single-layer optics-only (no decoder) and modest
by construction; the +0.1650 isolates the lever, NOT a headline accuracy.
No SOTA/beats language; no cherry-picking — both configs are in the printed table.
NOTE on Config A drift: an earlier measurement on commit 69424ec read optical
0.7420 (-1.20pp, acceptance PASS). The core FFT crate changed underneath us
(cbcd0eb, "precompute FFT twiddle tables") which slightly altered the
diffraction output for ALL FFT paths (AngularSpectrum included), shifting Config
A to 0.7305 (-2.35pp). Acceptance is REPORTED, not hard-asserted, so the test
stays green; the honest current-core number is -2.35pp. Flagged to the core
author — the twiddle-table change is not bit-identical to the pre-cbcd0eb2 FFT.
Scope: photonlayer-bench only (mnist_bench.rs + integration test). Core untouched.
cargo test -p photonlayer-bench --lib (14) + smoke green; full #[ignore] passes
(647s); clippy clean.
Co-Authored-By: claude-flow <ruv@ruv.net>
* test(photonlayer-bench): document the Config-A hill-climb optimizer ceiling
Adds run_mnist_config_a (fast Config-A-only harness) and a permanent #[ignore]
iteration sweep proving the -2pp acceptance line is NOT a training-budget issue
on the drift-corrected (post-cbcd0eb2) FFT core. Measured (seed 0x6e157,
4000 train / 2000 blind test):
iters 1500 -> optical 73.05% (-2.35pp)
iters 3000 -> optical 73.25% (-2.15pp)
iters 4500 -> optical 73.20% (-2.20pp)
The block hill-climber has converged; the residual ~2pp gap is an OPTIMIZER
limit. Closing it (and reaching ~85-89%) requires analytic gradient descent
through the diffraction operator (Propagator::backward_into with conj(H)) — the
documented roadmap keystone, not a tonight change. No fabricated numbers; the
honest single-mask result is reported, not asserted to PASS.
Co-Authored-By: claude-flow <ruv@ruv.net>
* docs(photonlayer): M3 — refresh ASSESSMENT to shipped numbers + optimizer-ceiling honesty
The pre-OPT-B -1.20pp figure was stale after the twiddle-table FFT change.
Updates Config A to the true converged number on the optimized core
(73.05% / -2.35pp at 16x/16x; +8.10pp learned-vs-random), adds Config B
(+16.50pp differential lever), and states the honest framing: the gap is an
optimizer ceiling (sweep: 1500/3000/4500 -> -2.35/-2.15/-2.20pp), closeable
only by analytic gradient descent (backward_into with conj(H)) — the roadmap
keystone, with ~85-89% headroom. No PASS asserted that the method cannot reach.
Co-Authored-By: claude-flow <ruv@ruv.net>
* fix(photonlayer-bench): rustfmt + doc_lazy_continuation lint
- cargo fmt on all photonlayer crates
- Fix doc comment: `+` on continuation line parsed as markdown list
marker causing clippy::doc_lazy_continuation. Changed to prose `and`.
Co-Authored-By: claude-flow <ruv@ruv.net>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ruv <ruvnet@users.noreply.github.com>
Co-authored-by: ruvnet <ruvnet@gmail.com>1 parent a73accc commit 2b7dbc7
53 files changed
Lines changed: 9024 additions & 165 deletions
File tree
- crates
- photonlayer-bench
- src
- bin
- tests
- photonlayer-cli
- src
- photonlayer-core
- src
- tests
- photonlayer-ruvector
- src
- photonlayer-wasm
- src
- docs
- adr
- research/photonlayer
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
112 | 115 | | |
113 | 116 | | |
114 | 117 | | |
| |||
0 commit comments