memlnaut-nisps/tests/cpp
monkey-w1n5t0n f57cddc278 fix(ml): port RMSProp — ported learning rates were landing in SGD
Upstream memlp (github.com/MusicallyEmbodiedML/memlp @ ea777502, the commit
upstream/main pins) applies gradients with RMSProp everywhere: Layer.h:239
ApplyAccumulatedGradients, the m_sq_grad_avg running average at Layer.h:601,
StaticMLP.h:268. nisps/ml/training.hpp shipped SGD only and filed the
difference as an optimiser-choice research question. It was not one.

RMSProp divides each step by the running gradient magnitude, so an upstream
lr is a NORMALISED step; under SGD the same number multiplies the raw
gradient. Every learning rate ported from upstream therefore landed in an
optimiser that reads it differently — most visibly feedback.hpp's
`geo_lr_ = 0.001f  // upstream InterfaceRL.hpp:312`, an RMSProp LR pasted
into a single SGD step.

rmsprop_step() ports Layer.h:239 exactly: clip at +/-10, sq = min(0.9*sq +
0.1*g^2, 1e6), adj = min(lr/(sqrt(sq)+1e-6), 1.0), w -= adj*g. The
adjusted-LR clamp stays one-sided as upstream's std::min is, so the negative
lr used by train_targets' "train away from this target" path behaves as it
does upstream. The per-weight squared-gradient average is new persistent
state and lives in the storage policies (FixedStorage arrays /
DynamicStorage arena) so nisps/ stays allocation-free and the firmware's
zero-heap contract holds. It is optimiser state, not model state: excluded
from weight_count()/get_weights()/set_weights(), matching upstream, and
cleared by MLPCore::reset_optimizer_state() (upstream ResetOptimizerState).
draw_weights() deliberately does NOT clear it — upstream's DrawWeights
doesn't either.

Measured with tests/cpp/ml_bench.cpp:
  D1  one geometric dislike moves the mapping 1.6e-2, up from 5.3e-5 (~295x),
      and repeated presses now CONVERGE on the intended 0.5 push (0.12 at 10,
      0.56 at 100) instead of creeping linearly forever.
  A4  geometric-vs-Diffuse gap narrows from ~4100x to ~14x in one press.
  U4  the upstream-LR positive path actually trains now (range_util 0.71 at
      100 ticks/gesture, was 0.016 — it was inert under SGD).
Not fixed by this, and now tracked as ALIGNMENT defect 6d: the dose
asymmetry. lurch_max is still ~1.08 against a [0,1] output range.

Golden vector stages 2 and 3 re-captured; stages 0 and 1 are pre-training
and did not move, which is the cross-check that only the update rule
changed. manifold/public/nisps.wasm rebuilt so parity-check compares like
with like — it FAILED at up to 5e-2 against the stale artifact and PASSES at
2.4e-7 against a fresh one. parity-check.sh only builds the WASM when it is
missing, never when it is stale; noted in MAP.md and filed separately.

ALIGNMENT defect 6 resolved (moved to Recently resolved); 6b's optimiser
cross-reference updated; new defect 6d for the positive-training dose.

Gates: build-cpp-tests 138 tests / ctest 4/4, parity-check PASS, lint-cpp
clean, manifold typecheck clean.
2026-07-25 11:11:23 +02:00
..
.gitignore Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
bench_report.mjs feat: curve truth, DriverConfig, real telemetry, engine benchmark 2026-07-21 22:02:23 +02:00
engine_bench.cpp feat: curve truth, DriverConfig, real telemetry, engine benchmark 2026-07-21 22:02:23 +02:00
engine_impulse.cpp Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
engine_impulse_baseline.bin Stream 11: verification infrastructure (golden vectors + parity + lint + CI + Playwright migration) 2026-04-29 19:50:55 +03:00
ml_bench.cpp test(ml): behavioural benchmark + 20 invariants for the control mapping 2026-07-25 11:02:24 +02:00
ml_golden_vectors.cpp fix(ml): port RMSProp — ported learning rates were landing in SGD 2026-07-25 11:11:23 +02:00
parity_check.cpp fix(gates): close the no-heap lint's false negatives and parity's silent FAIL 2026-07-21 13:23:11 +02:00
parity_diff.mjs feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/ 2026-07-18 11:52:53 +02:00
parity_wasm.mjs fix(ml): one named example capacity; train() and trainAsync() no longer diverge 2026-07-21 13:22:38 +02:00
test_dsp_biquad.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_delay.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_pitch_shift.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_reverb.cpp feat(nisps/dsp): lean DSP primitives ported from maximilian (meml-1v6) 2026-04-29 16:08:49 +03:00
test_dsp_seq_shared.cpp refactor(engines): extract the shared sequencer machinery 2026-07-21 14:02:23 +02:00
test_engine_analysis.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_breakor.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_channel_strip.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_elysiamorf.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_memlcelium.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_no_op.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_paf_synth.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_verb_fx.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_engine_xiasri.cpp feat(nisps/engines): port firmware audio engines to AudioEngine concept (meml-1v6) 2026-04-29 16:09:12 +03:00
test_helpers.hpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_main.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_math.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_ml_behaviour.cpp test(ml): behavioural benchmark + 20 invariants for the control mapping 2026-07-25 11:02:24 +02:00
test_mlp_feedback.cpp feat(ml)!: P3 core — geometric dislike in nisps/, jolt/OU + geo ABI 2026-07-14 04:16:21 +02:00
test_mlp_geo_dislike.cpp refactor(nisps): delete dead core/ML mass; keep the legacy feedback modes 2026-07-21 12:48:27 +02:00
test_mlp_inference.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_init.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_jolt.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mlp_loss.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_ou_noise.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mlp_rl.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_serialize.cpp feat(nisps/ml): MLP library with fixed-architecture template + spread-aware RL (meml-wmh) 2026-04-29 15:55:43 +03:00
test_mlp_storage_defaults.cpp fix(ml): one named example capacity; train() and trainAsync() no longer diverge 2026-07-21 13:22:38 +02:00
test_mlp_storage_parity.cpp feat(wasm)!: P2.2 — nisps_ml_create honours dims; runtime-shaped browser MLP + reshape 2026-07-14 03:38:06 +02:00
test_mlp_training.cpp feat: curve truth, DriverConfig, real telemetry, engine benchmark 2026-07-21 22:02:23 +02:00
test_mode_breakor_events.cpp test(nisps/modes): host C++ tests for stream 4 mode layer (meml-beb) 2026-04-29 16:27:03 +03:00
test_mode_concepts.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mode_curve_overrides.cpp feat: curve truth, DriverConfig, real telemetry, engine benchmark 2026-07-21 22:02:23 +02:00
test_mode_driver_config.cpp feat: curve truth, DriverConfig, real telemetry, engine benchmark 2026-07-21 22:02:23 +02:00
test_mode_learning.cpp feat(slp-workshop): new MEMLCelium-based mode + port Jolt & OU-noise RL learning 2026-06-28 22:15:36 +02:00
test_mode_paf_synth.cpp feat(modes): ModeBase input-pin API for single/dual joystick 2026-06-28 21:17:51 +02:00
test_mode_voice_space.cpp test(nisps/modes): host C++ tests for stream 4 mode layer (meml-beb) 2026-04-29 16:27:03 +03:00
test_pipeline.cpp feat(pipeline)!: P4 core — input/output chains + curve catalog in nisps/ 2026-07-18 11:52:53 +02:00
test_ring_buffer.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_rng.cpp feat: nisps build + host test harness 2026-04-29 15:22:01 +03:00
test_vcv_iml_parity.cpp feat(vcv): reunify module onto core MLP — thin iml.hpp adapter (P6) 2026-07-18 13:01:28 +02:00