Geometric dislike (rl-feedback-design §2.1/§4; upstream InterfaceRL @
0a541cc ported verbatim, constants included):
- nisps/ml/replay.hpp: ReplayView over storage-owned buffers — deepen-or-
store negatives (dedup 0.05, clamp -16), k-NN positive centroid with
deterministic index tie-break + fixed accumulation order, proportional
decay (0.0025*max(|r|,1)) + eviction, order-preserving compaction.
- nisps/ml/geo_push.hpp: push-away target (pushStep clamp(|avgNeg|,.25,1)
*0.5, taper /(1+len), useRandom on len<=1e-4 via nisps::Rng — the single
deliberate divergence from libc rand()), negLRRatio 0.5-0.4*negFraction.
- mlp.hpp: train_targets(input, computed-target, lr, out_mask) — trains
toward computed targets (negative lr = cold-start train-away); solo/
focus gating zeroes masked derivs.
- feedback.hpp: AvoidStyle {Geometric (new default), Diffuse (legacy
move_weights, kept for A/B)}; dislike_geometric() collapses upstream's
press+optimise into one synchronous call; on_up in geometric Avoid
feeds the positive centroid; dislike-multiplier bookkeeping. Storage
gains replay buffers (Fixed: ReplayCap=32 firmware default ≈ +8KB SRAM;
Dynamic arena: cap 64).
- bindings: nisps_ml_feedback_{dislike_geometric,store_positive,
positive_count,negative_count,set_avoid_style} + P3.2 jolt/OU ABI:
nisps_ml_jolt_{press,step,release,active,lr_scale,tick_lr_ramp},
nisps_ml_explore_{intensity,get_intensity,apply} (OUNoise<4096>
over-provisioned; same code the firmware ModeBase runs).
- parity v4: Stage 6 scripted geometric session (2 likes → 2 dislikes,
f32-exact heard vectors via Math.fround) — 961 floats PASS at 2.4e-7.
- tests: test_mlp_geo_dislike.cpp (replay dedup/deepen/clamp, centroid
tie-break, push direction/taper/mask/clamp, cold-start inertness +
train-away, determinism, Diffuse legacy); legacy Avoid test pinned to
Diffuse per the ADR's deliberate-break note.
Firmware: PAFSynth .text/.data unchanged (geometric path not referenced
by current glue). NOTE: discovered pre-existing bug 10c3e55c — the
explore/place wiring is linker-GC'd out of the PAFSynth ELF (predates
this refactor; evidence in the ergo task).
|
||
|---|---|---|
| .. | ||
| bindings.cpp | ||
| README.md | ||
nisps/wasm
Emscripten target that exposes nisps/ml (MLP) and nisps/engines (audio
engines) to the browser apps via a flat C ABI.
This directory is a leaf — it does not export headers for inclusion by
other C++ code. The only artifact is bindings.cpp plus the build script
that turns it into manifold/public/nisps.{wasm,js} (with a transitional
copy to playground/public/ until P1 of
docs/specs/plans/one-core-engine-refactor.md retires the playground).
Building
scripts/build-wasm.sh
Requires emcc (Emscripten). The script defaults to
/usr/lib/emscripten/emcc and respects an EMCC env var override.
Output:
manifold/public/nisps.wasm— the compiled module.manifold/public/nisps.js— Emscripten glue (factory functioncreateNispsModule, MODULARIZE=1).
Both files are committed (so the browser apps work from a fresh clone
without a C++ toolchain). Re-run build-wasm.sh after changes to
nisps/{core,ml,engines,wasm}.
Architecture (runtime-shaped since one-core-engine P2)
The browser MLP is MLPCore<DynamicStorage> (nisps/ml/dynamic_storage.hpp):
nisps_ml_create(input, output, hidden[3], n, seed) HONOURS its dimensions.
The 4-layer topology (ReLU×3 + Sigmoid) is fixed; only the dimensions are
runtime, capped at 4096 per dim. Non-positive/null arguments fall back to the
historical defaults:
32 inputs → [10, 14, 18] hidden → 126 outputs
nisps_ml_reshape(ml, in, out, hidden, n, spread) constructs a new net at
the requested shape, warm-starts it by copying the overlapping weight region
(nisps/ml/warm_start.hpp), and swaps it in. The C-side dataset and the
feedback controller state RESET on reshape (front-end shows a confirm modal).
Heap is used only at create/reshape time, never per-call; the firmware target
never compiles the dynamic storage at all (#error under
NISPS_TARGET_EMBEDDED).
C API surface
See bindings.cpp for the full list. Summary:
| Group | Functions |
|---|---|
| ML life | nisps_ml_create, nisps_ml_destroy, nisps_ml_reset, nisps_ml_reshape |
| ML I/O | nisps_ml_set_input, nisps_ml_process, nisps_ml_outputs, nisps_ml_infer_batch |
| Training | nisps_ml_add_example, nisps_ml_train, nisps_ml_eval_loss, nisps_ml_clear_examples, nisps_ml_example_count |
| Weights | nisps_ml_weight_count, nisps_ml_get_weights, nisps_ml_set_weights, nisps_ml_draw_weights, nisps_ml_move_weights |
| Diag | nisps_ml_get_layer_stats, nisps_ml_describe |
| Engines | nisps_engine_create, nisps_engine_destroy, nisps_engine_set_params, nisps_engine_process_block |
Engine-id strings follow the C++ engine_id() constexpr accessors:
thru, paf_synth, channel_strip, xiasri, verb_fx, memlcelium,
breakor, elysiamorf, analysis. Unknown ids fall back to thru
(silent passthrough).