From b16f26e6abec841677a18330af1acf5a325e9d79 Mon Sep 17 00:00:00 2001 From: monkey-w1n5t0n Date: Tue, 21 Jul 2026 17:20:10 +0200 Subject: [PATCH] refactor(ml): one runtime-configurable training default (S26) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The operator's call: "there should be one default learning rate and one default max iterations and they should both be configurable at runtime." There were SIX copies, not the four the audit described, and they did not agree: nisps/ml/mlp.hpp no-arg train() hardcoding 1.f / 1000u / 0.001f — and firmware's ONLY training path calls exactly this, so firmware had no runtime knob at all wasm-iml.ts train() and trainAsync() TS default params (x2) engine-api.ts learningRate ?? 1.0, with no maxIterations knob vcv/src/iml.hpp 200 / 0.1 / 0.00001 — silently divergent external_synth_midi.hpp its own kDefaultLearningRate/kDefaultMaxIterations schemas/modes/*.json x9, identical, read by nobody at runtime Now: schemas/ml_defaults.json is the single declaration (validated against a sibling meta-schema, matching the midi_device.schema.json convention), codegen emits it to C++ and TS in the same run, and MLPCore carries a TrainConfig whose default member initialisers read the generated constant. set_train_config()/nisps_ml_set_train_config() make it runtime-overridable on every target; the explicit-argument train() overload is untouched. min_error joins the tuple — it was duplicated identically and belongs with the other two. The per-mode ml block loses default_learning_rate/default_max_iterations. default_spread stays (genuinely wired on both targets) and input_channels stays (codegen-time validated, real information for sound_analysis_midi). VCV BEHAVIOUR CHANGE, deliberate: MEMLNaut.cpp constructs IML positionally and relies on those defaults, so the module moves to 1000/1.0/0.001 — 5x the max iterations, 10x the learning rate, and a 100x looser early-stop threshold. The old values were never justified anywhere; they arrived with fbc68eb alongside an unrelated module rewrite and no tuning rationale. Firmware and WASM have shipped 1.0/1000 all along. It is now runtime-settable if this turns out worse. The generated header lands in nisps/ml/generated/, not nisps/modes/generated/ where the rest of codegen output lives: training hyperparameters are an ML fact, and nisps/ml sits below nisps/modes, so emitting them there would make mlp.hpp include upward. The agent that built this flagged the directory-crossing rather than hiding it; this is the fix. CI's generated-freshness gate learns the new directory. Gates: run-all-tests.sh ALL GREEN — 4/4 ctest, parity PASS (max delta 2.38e-7), lint clean, manifold typecheck + 17 unit + 33 e2e (which exercise train() and trainAsync() through a real browser). --- .github/workflows/ci.yml | 2 +- MAP.md | 4 +- codegen/generate.ts | 133 ++++++++++++++++-- codegen/tests/golden/paf_synth_schema.hpp | 4 - codegen/tests/golden/paf_synth_schema.ts | 2 - manifold/public/nisps.js | 2 +- manifold/public/nisps.wasm | Bin 130068 -> 130169 bytes manifold/src/engine/engine-api.ts | 16 ++- manifold/src/engine/types.ts | 3 + manifold/src/engine/wasm-iml.ts | 32 ++++- .../src/modes/generated/breakor_schema.ts | 2 - .../modes/generated/channel_strip_schema.ts | 2 - .../src/modes/generated/elysiamorf_schema.ts | 2 - .../src/modes/generated/memlcelium_schema.ts | 2 - manifold/src/modes/generated/ml_defaults.ts | 17 +++ .../src/modes/generated/paf_synth_schema.ts | 2 - .../modes/generated/slp_workshop_schema.ts | 2 - .../generated/sound_analysis_midi_schema.ts | 2 - manifold/src/modes/generated/types.ts | 2 - .../src/modes/generated/verb_fx_schema.ts | 2 - manifold/src/modes/generated/xiasri_schema.ts | 2 - nisps/ml/generated/ml_defaults.hpp | 29 ++++ nisps/ml/mlp.hpp | 43 +++++- nisps/modes/external_synth_midi.hpp | 12 +- nisps/modes/generated/breakor_schema.hpp | 4 - .../modes/generated/channel_strip_schema.hpp | 4 - nisps/modes/generated/elysiamorf_schema.hpp | 4 - nisps/modes/generated/memlcelium_schema.hpp | 4 - nisps/modes/generated/paf_synth_schema.hpp | 4 - nisps/modes/generated/schema_types.hpp | 4 - nisps/modes/generated/slp_workshop_schema.hpp | 4 - .../generated/sound_analysis_midi_schema.hpp | 4 - nisps/modes/generated/verb_fx_schema.hpp | 4 - nisps/modes/generated/xiasri_schema.hpp | 4 - nisps/wasm/bindings.cpp | 14 ++ schemas/ml_defaults.json | 7 + schemas/ml_defaults.schema.json | 31 ++++ schemas/modes/breakor.json | 4 +- schemas/modes/channel_strip.json | 4 +- schemas/modes/elysiamorf.json | 4 +- schemas/modes/memlcelium.json | 4 +- schemas/modes/paf_synth.json | 4 +- schemas/modes/slp_workshop.json | 4 +- schemas/modes/sound_analysis_midi.json | 4 +- schemas/modes/verb_fx.json | 4 +- schemas/modes/xiasri.json | 4 +- schemas/schema.json | 8 +- scripts/build-wasm.sh | 2 +- vcv/src/iml.hpp | 19 ++- 49 files changed, 342 insertions(+), 134 deletions(-) create mode 100644 manifold/src/modes/generated/ml_defaults.ts create mode 100644 nisps/ml/generated/ml_defaults.hpp create mode 100644 schemas/ml_defaults.json create mode 100644 schemas/ml_defaults.schema.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0ce74f..534e3f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,7 +116,7 @@ jobs: bun run generate-midi-devices.ts bun run tests/golden_test.ts cd .. - GEN_DIRS="nisps/modes/generated nisps/midi/generated \ + GEN_DIRS="nisps/modes/generated nisps/midi/generated nisps/ml/generated \ manifold/src/modes/generated manifold/src/midi-devices/generated" git add -N $GEN_DIRS if ! git diff --exit-code -- $GEN_DIRS; then diff --git a/MAP.md b/MAP.md index 9729905..b99ced5 100644 --- a/MAP.md +++ b/MAP.md @@ -6,7 +6,7 @@ MEMLNaut-NISPS — Neural Interactive Shaping of Parameter Spaces. One C++20 cod ### `nisps/` — platform-agnostic C++20 library (the only ML/DSP/engine code) - `nisps/core/` — `perf.hpp` (hot-path/inlining attrs), `types.hpp`, `concepts.hpp` (`MLEngine`, `AudioEngine`, `Mode`), `ring_buffer.hpp` (SPSC lock-free cross-core channel, replaces pico/util/queue), `event_queue.hpp` (single-threaded in-engine event FIFO — deliberately NOT RingBuffer, which is an atomics-based cross-thread channel), `rng.hpp` (xoshiro256+ deterministic), `math.hpp` (fast_sigmoid, `Curve` enum + `apply_curve`). -- `nisps/ml/` — the MLP core, written once against a storage policy (`mlp.hpp` `MLPCore`): `storage.hpp` (`FixedStorage` — template-sized `std::array`, zero heap; `MLP` alias preserves the classic compile-time surface) and `dynamic_storage.hpp` (`DynamicStorage` — runtime dims, single arena alloc at construction; `#error`s on RP2350 builds, sole lint heap-allowlist entry). Fixed↔dynamic bit-parity enforced by `tests/cpp/test_mlp_storage_parity.cpp`. Files: `mlp.hpp`, `activations.hpp`, `loss.hpp` (MSE, no double-scaling), `training.hpp` (SGD + grad clipping), `init.hpp` (spread-aware uniform↔Xavier), `rl.hpp` (`move_weights` with output pin mask + per-layer scaling + weight decay), `jolt.hpp` (`Jolt` — held continuous weight-morph over the flat weight buffer + post-release LR ramp; ported from upstream InterfaceRL), `ou_noise.hpp` (`OUNoise` — Ornstein-Uhlenbeck exploration walk on the output vector; ported from upstream InterfaceRL), `feedback.hpp` (`FeedbackControllerCore` — the "Down Action" state machine: Avoid (geometric push-away default / Diffuse legacy) / RandomiseOutputs / RandomiseMlp / ExploreAndPlace; storage-policied like the MLP, own deterministic RNG, exposed via `nisps_ml_feedback_*` C API), `replay.hpp` (`ReplayView` — reward-tagged memory: dedup/deepen, k-NN positive centroid with deterministic tie-break, proportional decay+eviction), `geo_push.hpp` (push-away target computation, upstream InterfaceRL @ 0a541cc), `warm_start.hpp` (overlapping-weights copy for reshape), `stats.hpp`. Jolt + OU are inert by default and wired into `ModeBase`, so every mode exposes `jolt_press/jolt_release`, `jolt_lr_scale`, and `set_explore_intensity`. +- `nisps/ml/` — the MLP core, written once against a storage policy (`mlp.hpp` `MLPCore`): `storage.hpp` (`FixedStorage` — template-sized `std::array`, zero heap; `MLP` alias preserves the classic compile-time surface) and `dynamic_storage.hpp` (`DynamicStorage` — runtime dims, single arena alloc at construction; `#error`s on RP2350 builds, sole lint heap-allowlist entry). Fixed↔dynamic bit-parity enforced by `tests/cpp/test_mlp_storage_parity.cpp`. Files: `mlp.hpp`, `activations.hpp`, `loss.hpp` (MSE, no double-scaling), `training.hpp` (SGD + grad clipping), `init.hpp` (spread-aware uniform↔Xavier), `rl.hpp` (`move_weights` with output pin mask + per-layer scaling + weight decay), `jolt.hpp` (`Jolt` — held continuous weight-morph over the flat weight buffer + post-release LR ramp; ported from upstream InterfaceRL), `ou_noise.hpp` (`OUNoise` — Ornstein-Uhlenbeck exploration walk on the output vector; ported from upstream InterfaceRL), `feedback.hpp` (`FeedbackControllerCore` — the "Down Action" state machine: Avoid (geometric push-away default / Diffuse legacy) / RandomiseOutputs / RandomiseMlp / ExploreAndPlace; storage-policied like the MLP, own deterministic RNG, exposed via `nisps_ml_feedback_*` C API), `replay.hpp` (`ReplayView` — reward-tagged memory: dedup/deepen, k-NN positive centroid with deterministic tie-break, proportional decay+eviction), `geo_push.hpp` (push-away target computation, upstream InterfaceRL @ 0a541cc), `warm_start.hpp` (overlapping-weights copy for reshape), `stats.hpp`. `generated/ml_defaults.hpp` is codegen output (do not edit): `nisps::ml::generated::kMlTrainDefaults`, the ONE learning-rate / max-iterations / min-error default shared by firmware, WASM and VCV (source `schemas/ml_defaults.json`); `MLPCore::set_train_config()` and `nisps_ml_set_train_config()` override it at runtime. It lives under `ml/` rather than `modes/generated/` because `nisps/ml` sits below `nisps/modes` — mlp.hpp must not include upward. Jolt + OU are inert by default and wired into `ModeBase`, so every mode exposes `jolt_press/jolt_release`, `jolt_lr_scale`, and `set_explore_intensity`. - `nisps/pipeline/` — the control-rate input/output processing chains (P4): `input_chain.hpp` (`InputChain` — invert→deadzone→circular clamp→momentum-modulated zoom→centred power→EMA→momentum; caller-supplied dt, internal clock, fixed velocity ring, serialisable state) and `output_chain.hpp` (`OutputChain` — curve→EMA→slew→freeze(+mask), capacity-templated). Behaviour contract = the retired manifold TS pipelines, pinned by `manifold/tests/fixtures/` and parity stage 7. - `nisps/dsp/` — `biquad.hpp`, `delay.hpp`, `reverb.hpp`, `filter.hpp`, `env.hpp`, `osc.hpp`, `pitch_shift.hpp`, `dc_blocker.hpp`, plus the sequencer primitives shared by the sequencer engines: `ratio_seq.hpp` and `seq_clock.hpp` (bar phasor + MIDI clock + bpm). Lean primitives extracted from maximilian; daisysp PitchShifter replaced with custom granular impl. - `nisps/engines/` — eight audio engines, each satisfying `AudioEngine`: `paf_synth.hpp`, `channel_strip.hpp`, `xiasri.hpp`, `verb_fx.hpp`, `memlcelium.hpp`, `breakor.hpp` (sequencer, NoOp audio), `elysiamorf.hpp` (sequencer, NoOp audio), `analysis.hpp` (input-side spectral features). Plus `base.hpp` (`NoOpEngine`, engine_id "thru"). @@ -141,7 +141,7 @@ includes; no `nisps-core`. - **Parity check**: `bash scripts/parity-check.sh`. - **All tests**: `bash scripts/run-all-tests.sh`. - **Playwright**: `cd manifold && node node_modules/.bin/playwright test` (non-snap node runner on the VPS — BUILD-PLAN gotcha; `bunx playwright test` works elsewhere). -- **Codegen**: `cd codegen && bun run generate.ts` (regenerates both `nisps/modes/generated/` C++ and `manifold/src/modes/generated/` TS). +- **Codegen**: `cd codegen && bun run generate.ts` (regenerates `nisps/modes/generated/` + `nisps/ml/generated/` C++ and `manifold/src/modes/generated/` TS). ## Conventions diff --git a/codegen/generate.ts b/codegen/generate.ts index d2585d4..ed70851 100644 --- a/codegen/generate.ts +++ b/codegen/generate.ts @@ -50,8 +50,6 @@ interface ModeSchema { hidden_layers: number[]; output_size: number; default_spread: number; - default_learning_rate: number; - default_max_iterations: number; }; params: Array<{ name: string; @@ -71,6 +69,24 @@ interface ModeSchema { }; } +/** + * The ONE global training-hyperparameter default (schemas/ml_defaults.json, + * validated against schemas/ml_defaults.schema.json) — NOT per-mode, unlike + * everything else in ModeSchema. See S26 (docs/specs/recon/ + * simplification-audit-2026-07.md): learning_rate/max_iterations/min_error + * used to be duplicated per-mode (identically, unread at runtime) plus + * hardcoded separately in nisps/ml/mlp.hpp, manifold/src/engine/wasm-iml.ts, + * and vcv/src/iml.hpp. Now declared once here and consumed by + * `nisps::ml::MLPCore`'s `TrainConfig` default member initialisers. + */ +interface MlTrainDefaults { + $schema?: string; + _note?: string; + learning_rate: number; + max_iterations: number; + min_error: number; +} + // ----- Path resolution ------------------------------------------------------ const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -78,7 +94,15 @@ const REPO_ROOT = resolve(__dirname, ".."); const SCHEMAS_DIR = join(REPO_ROOT, "schemas"); const MODES_DIR = join(SCHEMAS_DIR, "modes"); const META_SCHEMA_PATH = join(SCHEMAS_DIR, "schema.json"); +const ML_DEFAULTS_PATH = join(SCHEMAS_DIR, "ml_defaults.json"); +const ML_DEFAULTS_SCHEMA_PATH = join(SCHEMAS_DIR, "ml_defaults.schema.json"); const CPP_OUT_DIR = join(REPO_ROOT, "nisps", "modes", "generated"); +// The training defaults are an ML fact, not a mode fact, and `nisps/ml` sits +// BELOW `nisps/modes` in the layering MAP.md documents — emitting them into +// modes/generated/ would make mlp.hpp include upward. They get their own +// output dir on the C++ side. The TS side has no such layering to respect, so +// it keeps everything generated under one directory. +const CPP_ML_OUT_DIR = join(REPO_ROOT, "nisps", "ml", "generated"); const TS_OUT_DIR = join(REPO_ROOT, "manifold", "src", "modes", "generated"); // ----- Helpers -------------------------------------------------------------- @@ -173,8 +197,6 @@ function emitSchemaTypesHpp(): string { " std::size_t input_size;", " std::size_t output_size;", " float default_spread;", - " float default_learning_rate;", - " std::size_t default_max_iterations;", "};", "", "enum class PrimaryInput : unsigned char {", @@ -209,8 +231,6 @@ function emitSchemaTypesHpp(): string { " std::span hidden_layers;", " std::size_t output_size;", " float default_spread;", - " float default_learning_rate;", - " std::size_t default_max_iterations;", " std::span params;", " std::span voice_spaces;", " ::nisps::modes::generated::UIConfig ui;", @@ -261,8 +281,6 @@ function emitSharedTsTypes(): string { " readonly hidden_layers: readonly number[];", " readonly output_size: number;", " readonly default_spread: number;", - " readonly default_learning_rate: number;", - " readonly default_max_iterations: number;", "}", "", "export interface UIConfig {", @@ -325,8 +343,6 @@ function emitModeHpp(schema: ModeSchema, sourceFile: string): string { lines.push(` ${schema.ml.input_size}u,`); lines.push(` ${schema.ml.output_size}u,`); lines.push(` ${cppFloatLit(schema.ml.default_spread)},`); - lines.push(` ${cppFloatLit(schema.ml.default_learning_rate)},`); - lines.push(` ${schema.ml.default_max_iterations}u,`); lines.push("};"); lines.push(""); @@ -399,8 +415,6 @@ function emitModeHpp(schema: ModeSchema, sourceFile: string): string { lines.push(` std::span(${constName}HiddenLayers),`); lines.push(` ${constName}MLConfig.output_size,`); lines.push(` ${constName}MLConfig.default_spread,`); - lines.push(` ${constName}MLConfig.default_learning_rate,`); - lines.push(` ${constName}MLConfig.default_max_iterations,`); lines.push(` std::span(${constName}Params),`); lines.push(` std::span(${constName}VoiceSpaces),`); lines.push(` ${constName}UI,`); @@ -452,8 +466,6 @@ function emitModeTs(schema: ModeSchema, sourceFile: string): string { lines.push(" ],"); lines.push(` output_size: ${schema.ml.output_size},`); lines.push(` default_spread: ${schema.ml.default_spread},`); - lines.push(` default_learning_rate: ${schema.ml.default_learning_rate},`); - lines.push(` default_max_iterations: ${schema.ml.default_max_iterations},`); lines.push(" },"); lines.push(" params: ["); for (const p of schema.params) { @@ -519,6 +531,73 @@ function emitTsIndex(modeIds: string[]): string { return lines.join("\n"); } +// ----- Global ML-defaults emission (S26) ------------------------------------ +// The ONE learning_rate/max_iterations/min_error default (schemas/ml_defaults. +// json), NOT per-mode — emitted once, alongside schema_types.hpp/types.ts, +// rather than once per mode file like everything else in this module. + +const AUTOGEN_BANNER_ML_DEFAULTS = (lang: "C++" | "TS"): string => + `// AUTOGENERATED (${lang}) — do not edit. Source: schemas/ml_defaults.json. ` + + "Run `bun run codegen/generate.ts` to regenerate."; + +function emitMlDefaultsHpp(d: MlTrainDefaults): string { + return [ + AUTOGEN_BANNER_ML_DEFAULTS("C++"), + "// The ONE global training-hyperparameter default, shared by every mode on", + "// every platform (firmware/WASM/VCV) — see docs/specs/recon/", + "// simplification-audit-2026-07.md S26. Consumed by", + "// nisps::ml::MLPCore::TrainConfig's default member initialisers", + "// (nisps/ml/mlp.hpp); nisps_ml_set_train_config() and", + "// nisps::ml::MLPCore::set_train_config() make it runtime-overridable.", + "#ifndef NISPS_ML_GENERATED_ML_DEFAULTS_HPP", + "#define NISPS_ML_GENERATED_ML_DEFAULTS_HPP", + "", + "#include ", + "", + "namespace nisps::ml::generated {", + "", + "struct MlTrainDefaults {", + " float learning_rate;", + " std::size_t max_iterations;", + " float min_error;", + "};", + "", + "inline constexpr MlTrainDefaults kMlTrainDefaults = {", + ` ${cppFloatLit(d.learning_rate)},`, + ` ${d.max_iterations}u,`, + ` ${cppFloatLit(d.min_error)},`, + "};", + "", + "} // namespace nisps::ml::generated", + "", + "#endif // NISPS_ML_GENERATED_ML_DEFAULTS_HPP", + "", + ].join("\n"); +} + +function emitMlDefaultsTs(d: MlTrainDefaults): string { + return [ + AUTOGEN_BANNER_ML_DEFAULTS("TS"), + "// The ONE global training-hyperparameter default, shared by every mode on", + "// every platform — see docs/specs/recon/simplification-audit-2026-07.md S26.", + "// Consumed by WasmIML's train()/trainAsync() default parameters and", + "// EngineApi's learningRate/maxIterations options (manifold/src/engine/).", + "", + "export interface MlTrainDefaults {", + " readonly learningRate: number;", + " readonly maxIterations: number;", + " readonly minError: number;", + "}", + "", + "export const ML_TRAIN_DEFAULTS: MlTrainDefaults = {", + ` learningRate: ${d.learning_rate},`, + ` maxIterations: ${d.max_iterations},`, + ` minError: ${d.min_error},`, + "};", + "", + ].join("\n"); +} + // ----- Driver -------------------------------------------------------------- function main(): number { @@ -539,6 +618,29 @@ function main(): number { }); const validate = ajv.compile(metaSchema); + // 1b. Load, compile, and validate the ONE global ML training default + // (schemas/ml_defaults.json against schemas/ml_defaults.schema.json — S26, + // NOT per-mode, so it lives outside the modeFiles loop below). + if (!existsSync(ML_DEFAULTS_SCHEMA_PATH)) { + console.error(`error: ml-defaults meta-schema not found at ${ML_DEFAULTS_SCHEMA_PATH}`); + return 1; + } + if (!existsSync(ML_DEFAULTS_PATH)) { + console.error(`error: ml-defaults data not found at ${ML_DEFAULTS_PATH}`); + return 1; + } + const mlDefaultsSchema = readJSON(ML_DEFAULTS_SCHEMA_PATH); + const validateMlDefaults = ajv.compile(mlDefaultsSchema); + const mlDefaultsRaw = readJSON(ML_DEFAULTS_PATH); + if (!validateMlDefaults(mlDefaultsRaw)) { + console.error(`error: ${ML_DEFAULTS_PATH}: schema validation failed:`); + for (const err of validateMlDefaults.errors ?? []) { + console.error(` ${err.instancePath || ""} ${err.message}`); + } + return 1; + } + const mlDefaults = mlDefaultsRaw as MlTrainDefaults; + // 2. Discover all mode schemas if (!existsSync(MODES_DIR)) { console.error(`error: modes directory not found at ${MODES_DIR}`); @@ -620,6 +722,8 @@ function main(): number { // 4. Emit C++ outputs ensureDir(CPP_OUT_DIR); writeFileSync(join(CPP_OUT_DIR, "schema_types.hpp"), emitSchemaTypesHpp()); + ensureDir(CPP_ML_OUT_DIR); + writeFileSync(join(CPP_ML_OUT_DIR, "ml_defaults.hpp"), emitMlDefaultsHpp(mlDefaults)); for (const { source, schema } of schemas) { const out = join(CPP_OUT_DIR, `${schema.mode_id}_schema.hpp`); writeFileSync(out, emitModeHpp(schema, source)); @@ -628,6 +732,7 @@ function main(): number { // 5. Emit TS outputs ensureDir(TS_OUT_DIR); writeFileSync(join(TS_OUT_DIR, "types.ts"), emitSharedTsTypes()); + writeFileSync(join(TS_OUT_DIR, "ml_defaults.ts"), emitMlDefaultsTs(mlDefaults)); for (const { source, schema } of schemas) { const out = join(TS_OUT_DIR, `${schema.mode_id}_schema.ts`); writeFileSync(out, emitModeTs(schema, source)); diff --git a/codegen/tests/golden/paf_synth_schema.hpp b/codegen/tests/golden/paf_synth_schema.hpp index 197c671..a202a12 100644 --- a/codegen/tests/golden/paf_synth_schema.hpp +++ b/codegen/tests/golden/paf_synth_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kPafSynthMLConfig = { 4u, 33u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kPafSynthParamCount = 33u; @@ -359,8 +357,6 @@ inline constexpr ::nisps::ParamSchema kPafSynthSchema = { std::span(kPafSynthHiddenLayers), kPafSynthMLConfig.output_size, kPafSynthMLConfig.default_spread, - kPafSynthMLConfig.default_learning_rate, - kPafSynthMLConfig.default_max_iterations, std::span(kPafSynthParams), std::span(kPafSynthVoiceSpaces), kPafSynthUI, diff --git a/codegen/tests/golden/paf_synth_schema.ts b/codegen/tests/golden/paf_synth_schema.ts index 6b66bc0..5890052 100644 --- a/codegen/tests/golden/paf_synth_schema.ts +++ b/codegen/tests/golden/paf_synth_schema.ts @@ -55,8 +55,6 @@ export const PafSynthSchema: ModeSchema = { ], output_size: 33, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/public/nisps.js b/manifold/public/nisps.js index 794bc3c..f47f693 100644 --- a/manifold/public/nisps.js +++ b/manifold/public/nisps.js @@ -6,7 +6,7 @@ var createNispsModule = (() => { function(moduleArg = {}) { var moduleRtn; -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&process.type!="renderer";var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){var preRuns=Module["preRun"];if(preRuns){if(typeof preRuns=="function")preRuns=[preRuns];preRuns.forEach(addOnPreRun)}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){var postRuns=Module["postRun"];if(postRuns){if(typeof postRuns=="function")postRuns=[postRuns];postRuns.forEach(addOnPostRun)}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){var f="nisps.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["d"];updateMemoryViews();addOnInit(wasmExports["e"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}wasmBinaryFile??=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var callRuntimeCallbacks=callbacks=>{callbacks.forEach(f=>f(Module))};var noExitRuntime=Module["noExitRuntime"]||true;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var __abort_js=()=>{abort("")};var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};var wasmImports={c:__abort_js,b:__emscripten_memcpy_js,a:_emscripten_resize_heap};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["e"])();var _nisps_ml_create=Module["_nisps_ml_create"]=(a0,a1,a2,a3,a4)=>(_nisps_ml_create=Module["_nisps_ml_create"]=wasmExports["f"])(a0,a1,a2,a3,a4);var _nisps_ml_reshape=Module["_nisps_ml_reshape"]=(a0,a1,a2,a3,a4,a5)=>(_nisps_ml_reshape=Module["_nisps_ml_reshape"]=wasmExports["g"])(a0,a1,a2,a3,a4,a5);var _nisps_ml_destroy=Module["_nisps_ml_destroy"]=a0=>(_nisps_ml_destroy=Module["_nisps_ml_destroy"]=wasmExports["h"])(a0);var _nisps_ml_set_input=Module["_nisps_ml_set_input"]=(a0,a1,a2)=>(_nisps_ml_set_input=Module["_nisps_ml_set_input"]=wasmExports["i"])(a0,a1,a2);var _nisps_ml_process=Module["_nisps_ml_process"]=a0=>(_nisps_ml_process=Module["_nisps_ml_process"]=wasmExports["j"])(a0);var _nisps_ml_outputs=Module["_nisps_ml_outputs"]=a0=>(_nisps_ml_outputs=Module["_nisps_ml_outputs"]=wasmExports["k"])(a0);var _nisps_ml_infer_batch=Module["_nisps_ml_infer_batch"]=(a0,a1,a2,a3)=>(_nisps_ml_infer_batch=Module["_nisps_ml_infer_batch"]=wasmExports["l"])(a0,a1,a2,a3);var _nisps_ml_add_example=Module["_nisps_ml_add_example"]=(a0,a1,a2)=>(_nisps_ml_add_example=Module["_nisps_ml_add_example"]=wasmExports["m"])(a0,a1,a2);var _nisps_ml_train=Module["_nisps_ml_train"]=(a0,a1,a2,a3,a4)=>(_nisps_ml_train=Module["_nisps_ml_train"]=wasmExports["n"])(a0,a1,a2,a3,a4);var _nisps_ml_eval_loss=Module["_nisps_ml_eval_loss"]=a0=>(_nisps_ml_eval_loss=Module["_nisps_ml_eval_loss"]=wasmExports["o"])(a0);var _nisps_ml_weight_count=Module["_nisps_ml_weight_count"]=a0=>(_nisps_ml_weight_count=Module["_nisps_ml_weight_count"]=wasmExports["p"])(a0);var _nisps_ml_get_weights=Module["_nisps_ml_get_weights"]=(a0,a1)=>(_nisps_ml_get_weights=Module["_nisps_ml_get_weights"]=wasmExports["q"])(a0,a1);var _nisps_ml_set_weights=Module["_nisps_ml_set_weights"]=(a0,a1)=>(_nisps_ml_set_weights=Module["_nisps_ml_set_weights"]=wasmExports["r"])(a0,a1);var _nisps_ml_draw_weights=Module["_nisps_ml_draw_weights"]=(a0,a1)=>(_nisps_ml_draw_weights=Module["_nisps_ml_draw_weights"]=wasmExports["s"])(a0,a1);var _nisps_ml_feedback_set_mode=Module["_nisps_ml_feedback_set_mode"]=(a0,a1)=>(_nisps_ml_feedback_set_mode=Module["_nisps_ml_feedback_set_mode"]=wasmExports["t"])(a0,a1);var _nisps_ml_feedback_get_mode=Module["_nisps_ml_feedback_get_mode"]=a0=>(_nisps_ml_feedback_get_mode=Module["_nisps_ml_feedback_get_mode"]=wasmExports["u"])(a0);var _nisps_ml_feedback_exploring=Module["_nisps_ml_feedback_exploring"]=a0=>(_nisps_ml_feedback_exploring=Module["_nisps_ml_feedback_exploring"]=wasmExports["v"])(a0);var _nisps_ml_feedback_set_focus=Module["_nisps_ml_feedback_set_focus"]=(a0,a1,a2)=>(_nisps_ml_feedback_set_focus=Module["_nisps_ml_feedback_set_focus"]=wasmExports["w"])(a0,a1,a2);var _nisps_ml_feedback_down=Module["_nisps_ml_feedback_down"]=(a0,a1,a2,a3,a4)=>(_nisps_ml_feedback_down=Module["_nisps_ml_feedback_down"]=wasmExports["x"])(a0,a1,a2,a3,a4);var _nisps_ml_feedback_up=Module["_nisps_ml_feedback_up"]=a0=>(_nisps_ml_feedback_up=Module["_nisps_ml_feedback_up"]=wasmExports["y"])(a0);var _nisps_ml_feedback_static_output=Module["_nisps_ml_feedback_static_output"]=(a0,a1)=>(_nisps_ml_feedback_static_output=Module["_nisps_ml_feedback_static_output"]=wasmExports["z"])(a0,a1);var _nisps_ml_feedback_enter_explore=Module["_nisps_ml_feedback_enter_explore"]=(a0,a1)=>(_nisps_ml_feedback_enter_explore=Module["_nisps_ml_feedback_enter_explore"]=wasmExports["A"])(a0,a1);var _nisps_ml_feedback_exit_explore=Module["_nisps_ml_feedback_exit_explore"]=a0=>(_nisps_ml_feedback_exit_explore=Module["_nisps_ml_feedback_exit_explore"]=wasmExports["B"])(a0);var _nisps_ml_feedback_reroll=Module["_nisps_ml_feedback_reroll"]=(a0,a1)=>(_nisps_ml_feedback_reroll=Module["_nisps_ml_feedback_reroll"]=wasmExports["C"])(a0,a1);var _nisps_ml_feedback_nudge=Module["_nisps_ml_feedback_nudge"]=(a0,a1)=>(_nisps_ml_feedback_nudge=Module["_nisps_ml_feedback_nudge"]=wasmExports["D"])(a0,a1);var _nisps_ml_feedback_undo=Module["_nisps_ml_feedback_undo"]=a0=>(_nisps_ml_feedback_undo=Module["_nisps_ml_feedback_undo"]=wasmExports["E"])(a0);var _nisps_ml_feedback_like=Module["_nisps_ml_feedback_like"]=a0=>(_nisps_ml_feedback_like=Module["_nisps_ml_feedback_like"]=wasmExports["F"])(a0);var _nisps_ml_feedback_commit_place=Module["_nisps_ml_feedback_commit_place"]=a0=>(_nisps_ml_feedback_commit_place=Module["_nisps_ml_feedback_commit_place"]=wasmExports["G"])(a0);var _nisps_ml_feedback_cancel_place=Module["_nisps_ml_feedback_cancel_place"]=a0=>(_nisps_ml_feedback_cancel_place=Module["_nisps_ml_feedback_cancel_place"]=wasmExports["H"])(a0);var _nisps_ml_feedback_undo_depth=Module["_nisps_ml_feedback_undo_depth"]=a0=>(_nisps_ml_feedback_undo_depth=Module["_nisps_ml_feedback_undo_depth"]=wasmExports["I"])(a0);var _nisps_ml_feedback_placed_output=Module["_nisps_ml_feedback_placed_output"]=(a0,a1)=>(_nisps_ml_feedback_placed_output=Module["_nisps_ml_feedback_placed_output"]=wasmExports["J"])(a0,a1);var _nisps_ml_feedback_dislike_geometric=Module["_nisps_ml_feedback_dislike_geometric"]=(a0,a1,a2)=>(_nisps_ml_feedback_dislike_geometric=Module["_nisps_ml_feedback_dislike_geometric"]=wasmExports["K"])(a0,a1,a2);var _nisps_ml_feedback_store_positive=Module["_nisps_ml_feedback_store_positive"]=(a0,a1)=>(_nisps_ml_feedback_store_positive=Module["_nisps_ml_feedback_store_positive"]=wasmExports["L"])(a0,a1);var _nisps_ml_feedback_positive_count=Module["_nisps_ml_feedback_positive_count"]=a0=>(_nisps_ml_feedback_positive_count=Module["_nisps_ml_feedback_positive_count"]=wasmExports["M"])(a0);var _nisps_ml_feedback_negative_count=Module["_nisps_ml_feedback_negative_count"]=a0=>(_nisps_ml_feedback_negative_count=Module["_nisps_ml_feedback_negative_count"]=wasmExports["N"])(a0);var _nisps_ml_feedback_set_avoid_style=Module["_nisps_ml_feedback_set_avoid_style"]=(a0,a1)=>(_nisps_ml_feedback_set_avoid_style=Module["_nisps_ml_feedback_set_avoid_style"]=wasmExports["O"])(a0,a1);var _nisps_ml_jolt_press=Module["_nisps_ml_jolt_press"]=a0=>(_nisps_ml_jolt_press=Module["_nisps_ml_jolt_press"]=wasmExports["P"])(a0);var _nisps_ml_jolt_step=Module["_nisps_ml_jolt_step"]=a0=>(_nisps_ml_jolt_step=Module["_nisps_ml_jolt_step"]=wasmExports["Q"])(a0);var _nisps_ml_jolt_release=Module["_nisps_ml_jolt_release"]=a0=>(_nisps_ml_jolt_release=Module["_nisps_ml_jolt_release"]=wasmExports["R"])(a0);var _nisps_ml_jolt_active=Module["_nisps_ml_jolt_active"]=a0=>(_nisps_ml_jolt_active=Module["_nisps_ml_jolt_active"]=wasmExports["S"])(a0);var _nisps_ml_explore_intensity=Module["_nisps_ml_explore_intensity"]=(a0,a1)=>(_nisps_ml_explore_intensity=Module["_nisps_ml_explore_intensity"]=wasmExports["T"])(a0,a1);var _nisps_ml_explore_get_intensity=Module["_nisps_ml_explore_get_intensity"]=a0=>(_nisps_ml_explore_get_intensity=Module["_nisps_ml_explore_get_intensity"]=wasmExports["U"])(a0);var _nisps_ml_explore_apply=Module["_nisps_ml_explore_apply"]=(a0,a1,a2)=>(_nisps_ml_explore_apply=Module["_nisps_ml_explore_apply"]=wasmExports["V"])(a0,a1,a2);var _nisps_ml_get_layer_stats=Module["_nisps_ml_get_layer_stats"]=(a0,a1)=>(_nisps_ml_get_layer_stats=Module["_nisps_ml_get_layer_stats"]=wasmExports["W"])(a0,a1);var _nisps_ml_clear_examples=Module["_nisps_ml_clear_examples"]=a0=>(_nisps_ml_clear_examples=Module["_nisps_ml_clear_examples"]=wasmExports["X"])(a0);var _nisps_ml_describe=Module["_nisps_ml_describe"]=(a0,a1)=>(_nisps_ml_describe=Module["_nisps_ml_describe"]=wasmExports["Y"])(a0,a1);var _nisps_pipeline_create=Module["_nisps_pipeline_create"]=()=>(_nisps_pipeline_create=Module["_nisps_pipeline_create"]=wasmExports["Z"])();var _nisps_pipeline_destroy=Module["_nisps_pipeline_destroy"]=a0=>(_nisps_pipeline_destroy=Module["_nisps_pipeline_destroy"]=wasmExports["_"])(a0);var _nisps_input_set_config=Module["_nisps_input_set_config"]=(a0,a1,a2)=>(_nisps_input_set_config=Module["_nisps_input_set_config"]=wasmExports["$"])(a0,a1,a2);var _nisps_input_process=Module["_nisps_input_process"]=(a0,a1,a2,a3,a4)=>(_nisps_input_process=Module["_nisps_input_process"]=wasmExports["aa"])(a0,a1,a2,a3,a4);var _nisps_input_reset=Module["_nisps_input_reset"]=a0=>(_nisps_input_reset=Module["_nisps_input_reset"]=wasmExports["ba"])(a0);var _nisps_output_set_config=Module["_nisps_output_set_config"]=(a0,a1,a2,a3,a4)=>(_nisps_output_set_config=Module["_nisps_output_set_config"]=wasmExports["ca"])(a0,a1,a2,a3,a4);var _nisps_output_set_freeze_mask=Module["_nisps_output_set_freeze_mask"]=(a0,a1,a2)=>(_nisps_output_set_freeze_mask=Module["_nisps_output_set_freeze_mask"]=wasmExports["da"])(a0,a1,a2);var _nisps_output_process=Module["_nisps_output_process"]=(a0,a1,a2,a3)=>(_nisps_output_process=Module["_nisps_output_process"]=wasmExports["ea"])(a0,a1,a2,a3);var _nisps_output_reset=Module["_nisps_output_reset"]=a0=>(_nisps_output_reset=Module["_nisps_output_reset"]=wasmExports["fa"])(a0);var _nisps_curve_apply=Module["_nisps_curve_apply"]=(a0,a1,a2)=>(_nisps_curve_apply=Module["_nisps_curve_apply"]=wasmExports["ga"])(a0,a1,a2);var _nisps_curve_apply_batch=Module["_nisps_curve_apply_batch"]=(a0,a1,a2,a3,a4)=>(_nisps_curve_apply_batch=Module["_nisps_curve_apply_batch"]=wasmExports["ha"])(a0,a1,a2,a3,a4);var _nisps_engine_create=Module["_nisps_engine_create"]=(a0,a1)=>(_nisps_engine_create=Module["_nisps_engine_create"]=wasmExports["ia"])(a0,a1);var _nisps_engine_destroy=Module["_nisps_engine_destroy"]=a0=>(_nisps_engine_destroy=Module["_nisps_engine_destroy"]=wasmExports["ja"])(a0);var _nisps_engine_set_params=Module["_nisps_engine_set_params"]=(a0,a1,a2)=>(_nisps_engine_set_params=Module["_nisps_engine_set_params"]=wasmExports["ka"])(a0,a1,a2);var _nisps_engine_process_block=Module["_nisps_engine_process_block"]=(a0,a1,a2,a3,a4,a5)=>(_nisps_engine_process_block=Module["_nisps_engine_process_block"]=wasmExports["la"])(a0,a1,a2,a3,a4,a5);var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["na"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["oa"])(a0);var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["pa"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["qa"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["ra"])();Module["ccall"]=ccall;Module["cwrap"]=cwrap;var calledRun;var calledPrerun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}if(!calledPrerun){calledPrerun=1;preRun();if(runDependencies>0){return}}function doRun(){if(calledRun)return;calledRun=1;Module["calledRun"]=1;if(ABORT)return;initRuntime();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run();moduleRtn=readyPromise; +var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&process.type!="renderer";var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=url=>fetch(url,{credentials:"same-origin"}).then(response=>{if(response.ok){return response.arrayBuffer()}return Promise.reject(new Error(response.status+" : "+response.url))})}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){var preRuns=Module["preRun"];if(preRuns){if(typeof preRuns=="function")preRuns=[preRuns];preRuns.forEach(addOnPreRun)}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function postRun(){var postRuns=Module["postRun"];if(postRuns){if(typeof postRuns=="function")postRuns=[postRuns];postRuns.forEach(addOnPostRun)}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){var f="nisps.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary){return readAsync(binaryFile).then(response=>new Uint8Array(response),()=>getBinarySync(binaryFile))}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{a:wasmImports}}function createWasm(){var info=getWasmImports();function receiveInstance(instance,module){wasmExports=instance.exports;wasmMemory=wasmExports["d"];updateMemoryViews();addOnInit(wasmExports["e"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}wasmBinaryFile??=findWasmBinary();instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var callRuntimeCallbacks=callbacks=>{callbacks.forEach(f=>f(Module))};var noExitRuntime=Module["noExitRuntime"]||true;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();var __abort_js=()=>{abort("")};var __emscripten_memcpy_js=(dest,src,num)=>HEAPU8.copyWithin(dest,src,src+num);var getHeapMax=()=>2147483648;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};var wasmImports={c:__abort_js,b:__emscripten_memcpy_js,a:_emscripten_resize_heap};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["e"])();var _nisps_ml_create=Module["_nisps_ml_create"]=(a0,a1,a2,a3,a4)=>(_nisps_ml_create=Module["_nisps_ml_create"]=wasmExports["f"])(a0,a1,a2,a3,a4);var _nisps_ml_reshape=Module["_nisps_ml_reshape"]=(a0,a1,a2,a3,a4,a5)=>(_nisps_ml_reshape=Module["_nisps_ml_reshape"]=wasmExports["g"])(a0,a1,a2,a3,a4,a5);var _nisps_ml_destroy=Module["_nisps_ml_destroy"]=a0=>(_nisps_ml_destroy=Module["_nisps_ml_destroy"]=wasmExports["h"])(a0);var _nisps_ml_set_input=Module["_nisps_ml_set_input"]=(a0,a1,a2)=>(_nisps_ml_set_input=Module["_nisps_ml_set_input"]=wasmExports["i"])(a0,a1,a2);var _nisps_ml_process=Module["_nisps_ml_process"]=a0=>(_nisps_ml_process=Module["_nisps_ml_process"]=wasmExports["j"])(a0);var _nisps_ml_outputs=Module["_nisps_ml_outputs"]=a0=>(_nisps_ml_outputs=Module["_nisps_ml_outputs"]=wasmExports["k"])(a0);var _nisps_ml_infer_batch=Module["_nisps_ml_infer_batch"]=(a0,a1,a2,a3)=>(_nisps_ml_infer_batch=Module["_nisps_ml_infer_batch"]=wasmExports["l"])(a0,a1,a2,a3);var _nisps_ml_add_example=Module["_nisps_ml_add_example"]=(a0,a1,a2)=>(_nisps_ml_add_example=Module["_nisps_ml_add_example"]=wasmExports["m"])(a0,a1,a2);var _nisps_ml_train=Module["_nisps_ml_train"]=(a0,a1,a2,a3,a4)=>(_nisps_ml_train=Module["_nisps_ml_train"]=wasmExports["n"])(a0,a1,a2,a3,a4);var _nisps_ml_set_train_config=Module["_nisps_ml_set_train_config"]=(a0,a1,a2,a3)=>(_nisps_ml_set_train_config=Module["_nisps_ml_set_train_config"]=wasmExports["o"])(a0,a1,a2,a3);var _nisps_ml_eval_loss=Module["_nisps_ml_eval_loss"]=a0=>(_nisps_ml_eval_loss=Module["_nisps_ml_eval_loss"]=wasmExports["p"])(a0);var _nisps_ml_weight_count=Module["_nisps_ml_weight_count"]=a0=>(_nisps_ml_weight_count=Module["_nisps_ml_weight_count"]=wasmExports["q"])(a0);var _nisps_ml_get_weights=Module["_nisps_ml_get_weights"]=(a0,a1)=>(_nisps_ml_get_weights=Module["_nisps_ml_get_weights"]=wasmExports["r"])(a0,a1);var _nisps_ml_set_weights=Module["_nisps_ml_set_weights"]=(a0,a1)=>(_nisps_ml_set_weights=Module["_nisps_ml_set_weights"]=wasmExports["s"])(a0,a1);var _nisps_ml_draw_weights=Module["_nisps_ml_draw_weights"]=(a0,a1)=>(_nisps_ml_draw_weights=Module["_nisps_ml_draw_weights"]=wasmExports["t"])(a0,a1);var _nisps_ml_feedback_set_mode=Module["_nisps_ml_feedback_set_mode"]=(a0,a1)=>(_nisps_ml_feedback_set_mode=Module["_nisps_ml_feedback_set_mode"]=wasmExports["u"])(a0,a1);var _nisps_ml_feedback_get_mode=Module["_nisps_ml_feedback_get_mode"]=a0=>(_nisps_ml_feedback_get_mode=Module["_nisps_ml_feedback_get_mode"]=wasmExports["v"])(a0);var _nisps_ml_feedback_exploring=Module["_nisps_ml_feedback_exploring"]=a0=>(_nisps_ml_feedback_exploring=Module["_nisps_ml_feedback_exploring"]=wasmExports["w"])(a0);var _nisps_ml_feedback_set_focus=Module["_nisps_ml_feedback_set_focus"]=(a0,a1,a2)=>(_nisps_ml_feedback_set_focus=Module["_nisps_ml_feedback_set_focus"]=wasmExports["x"])(a0,a1,a2);var _nisps_ml_feedback_down=Module["_nisps_ml_feedback_down"]=(a0,a1,a2,a3,a4)=>(_nisps_ml_feedback_down=Module["_nisps_ml_feedback_down"]=wasmExports["y"])(a0,a1,a2,a3,a4);var _nisps_ml_feedback_up=Module["_nisps_ml_feedback_up"]=a0=>(_nisps_ml_feedback_up=Module["_nisps_ml_feedback_up"]=wasmExports["z"])(a0);var _nisps_ml_feedback_static_output=Module["_nisps_ml_feedback_static_output"]=(a0,a1)=>(_nisps_ml_feedback_static_output=Module["_nisps_ml_feedback_static_output"]=wasmExports["A"])(a0,a1);var _nisps_ml_feedback_enter_explore=Module["_nisps_ml_feedback_enter_explore"]=(a0,a1)=>(_nisps_ml_feedback_enter_explore=Module["_nisps_ml_feedback_enter_explore"]=wasmExports["B"])(a0,a1);var _nisps_ml_feedback_exit_explore=Module["_nisps_ml_feedback_exit_explore"]=a0=>(_nisps_ml_feedback_exit_explore=Module["_nisps_ml_feedback_exit_explore"]=wasmExports["C"])(a0);var _nisps_ml_feedback_reroll=Module["_nisps_ml_feedback_reroll"]=(a0,a1)=>(_nisps_ml_feedback_reroll=Module["_nisps_ml_feedback_reroll"]=wasmExports["D"])(a0,a1);var _nisps_ml_feedback_nudge=Module["_nisps_ml_feedback_nudge"]=(a0,a1)=>(_nisps_ml_feedback_nudge=Module["_nisps_ml_feedback_nudge"]=wasmExports["E"])(a0,a1);var _nisps_ml_feedback_undo=Module["_nisps_ml_feedback_undo"]=a0=>(_nisps_ml_feedback_undo=Module["_nisps_ml_feedback_undo"]=wasmExports["F"])(a0);var _nisps_ml_feedback_like=Module["_nisps_ml_feedback_like"]=a0=>(_nisps_ml_feedback_like=Module["_nisps_ml_feedback_like"]=wasmExports["G"])(a0);var _nisps_ml_feedback_commit_place=Module["_nisps_ml_feedback_commit_place"]=a0=>(_nisps_ml_feedback_commit_place=Module["_nisps_ml_feedback_commit_place"]=wasmExports["H"])(a0);var _nisps_ml_feedback_cancel_place=Module["_nisps_ml_feedback_cancel_place"]=a0=>(_nisps_ml_feedback_cancel_place=Module["_nisps_ml_feedback_cancel_place"]=wasmExports["I"])(a0);var _nisps_ml_feedback_undo_depth=Module["_nisps_ml_feedback_undo_depth"]=a0=>(_nisps_ml_feedback_undo_depth=Module["_nisps_ml_feedback_undo_depth"]=wasmExports["J"])(a0);var _nisps_ml_feedback_placed_output=Module["_nisps_ml_feedback_placed_output"]=(a0,a1)=>(_nisps_ml_feedback_placed_output=Module["_nisps_ml_feedback_placed_output"]=wasmExports["K"])(a0,a1);var _nisps_ml_feedback_dislike_geometric=Module["_nisps_ml_feedback_dislike_geometric"]=(a0,a1,a2)=>(_nisps_ml_feedback_dislike_geometric=Module["_nisps_ml_feedback_dislike_geometric"]=wasmExports["L"])(a0,a1,a2);var _nisps_ml_feedback_store_positive=Module["_nisps_ml_feedback_store_positive"]=(a0,a1)=>(_nisps_ml_feedback_store_positive=Module["_nisps_ml_feedback_store_positive"]=wasmExports["M"])(a0,a1);var _nisps_ml_feedback_positive_count=Module["_nisps_ml_feedback_positive_count"]=a0=>(_nisps_ml_feedback_positive_count=Module["_nisps_ml_feedback_positive_count"]=wasmExports["N"])(a0);var _nisps_ml_feedback_negative_count=Module["_nisps_ml_feedback_negative_count"]=a0=>(_nisps_ml_feedback_negative_count=Module["_nisps_ml_feedback_negative_count"]=wasmExports["O"])(a0);var _nisps_ml_feedback_set_avoid_style=Module["_nisps_ml_feedback_set_avoid_style"]=(a0,a1)=>(_nisps_ml_feedback_set_avoid_style=Module["_nisps_ml_feedback_set_avoid_style"]=wasmExports["P"])(a0,a1);var _nisps_ml_jolt_press=Module["_nisps_ml_jolt_press"]=a0=>(_nisps_ml_jolt_press=Module["_nisps_ml_jolt_press"]=wasmExports["Q"])(a0);var _nisps_ml_jolt_step=Module["_nisps_ml_jolt_step"]=a0=>(_nisps_ml_jolt_step=Module["_nisps_ml_jolt_step"]=wasmExports["R"])(a0);var _nisps_ml_jolt_release=Module["_nisps_ml_jolt_release"]=a0=>(_nisps_ml_jolt_release=Module["_nisps_ml_jolt_release"]=wasmExports["S"])(a0);var _nisps_ml_jolt_active=Module["_nisps_ml_jolt_active"]=a0=>(_nisps_ml_jolt_active=Module["_nisps_ml_jolt_active"]=wasmExports["T"])(a0);var _nisps_ml_explore_intensity=Module["_nisps_ml_explore_intensity"]=(a0,a1)=>(_nisps_ml_explore_intensity=Module["_nisps_ml_explore_intensity"]=wasmExports["U"])(a0,a1);var _nisps_ml_explore_get_intensity=Module["_nisps_ml_explore_get_intensity"]=a0=>(_nisps_ml_explore_get_intensity=Module["_nisps_ml_explore_get_intensity"]=wasmExports["V"])(a0);var _nisps_ml_explore_apply=Module["_nisps_ml_explore_apply"]=(a0,a1,a2)=>(_nisps_ml_explore_apply=Module["_nisps_ml_explore_apply"]=wasmExports["W"])(a0,a1,a2);var _nisps_ml_get_layer_stats=Module["_nisps_ml_get_layer_stats"]=(a0,a1)=>(_nisps_ml_get_layer_stats=Module["_nisps_ml_get_layer_stats"]=wasmExports["X"])(a0,a1);var _nisps_ml_clear_examples=Module["_nisps_ml_clear_examples"]=a0=>(_nisps_ml_clear_examples=Module["_nisps_ml_clear_examples"]=wasmExports["Y"])(a0);var _nisps_ml_describe=Module["_nisps_ml_describe"]=(a0,a1)=>(_nisps_ml_describe=Module["_nisps_ml_describe"]=wasmExports["Z"])(a0,a1);var _nisps_pipeline_create=Module["_nisps_pipeline_create"]=()=>(_nisps_pipeline_create=Module["_nisps_pipeline_create"]=wasmExports["_"])();var _nisps_pipeline_destroy=Module["_nisps_pipeline_destroy"]=a0=>(_nisps_pipeline_destroy=Module["_nisps_pipeline_destroy"]=wasmExports["$"])(a0);var _nisps_input_set_config=Module["_nisps_input_set_config"]=(a0,a1,a2)=>(_nisps_input_set_config=Module["_nisps_input_set_config"]=wasmExports["aa"])(a0,a1,a2);var _nisps_input_process=Module["_nisps_input_process"]=(a0,a1,a2,a3,a4)=>(_nisps_input_process=Module["_nisps_input_process"]=wasmExports["ba"])(a0,a1,a2,a3,a4);var _nisps_input_reset=Module["_nisps_input_reset"]=a0=>(_nisps_input_reset=Module["_nisps_input_reset"]=wasmExports["ca"])(a0);var _nisps_output_set_config=Module["_nisps_output_set_config"]=(a0,a1,a2,a3,a4)=>(_nisps_output_set_config=Module["_nisps_output_set_config"]=wasmExports["da"])(a0,a1,a2,a3,a4);var _nisps_output_set_freeze_mask=Module["_nisps_output_set_freeze_mask"]=(a0,a1,a2)=>(_nisps_output_set_freeze_mask=Module["_nisps_output_set_freeze_mask"]=wasmExports["ea"])(a0,a1,a2);var _nisps_output_process=Module["_nisps_output_process"]=(a0,a1,a2,a3)=>(_nisps_output_process=Module["_nisps_output_process"]=wasmExports["fa"])(a0,a1,a2,a3);var _nisps_output_reset=Module["_nisps_output_reset"]=a0=>(_nisps_output_reset=Module["_nisps_output_reset"]=wasmExports["ga"])(a0);var _nisps_curve_apply=Module["_nisps_curve_apply"]=(a0,a1,a2)=>(_nisps_curve_apply=Module["_nisps_curve_apply"]=wasmExports["ha"])(a0,a1,a2);var _nisps_curve_apply_batch=Module["_nisps_curve_apply_batch"]=(a0,a1,a2,a3,a4)=>(_nisps_curve_apply_batch=Module["_nisps_curve_apply_batch"]=wasmExports["ia"])(a0,a1,a2,a3,a4);var _nisps_engine_create=Module["_nisps_engine_create"]=(a0,a1)=>(_nisps_engine_create=Module["_nisps_engine_create"]=wasmExports["ja"])(a0,a1);var _nisps_engine_destroy=Module["_nisps_engine_destroy"]=a0=>(_nisps_engine_destroy=Module["_nisps_engine_destroy"]=wasmExports["ka"])(a0);var _nisps_engine_set_params=Module["_nisps_engine_set_params"]=(a0,a1,a2)=>(_nisps_engine_set_params=Module["_nisps_engine_set_params"]=wasmExports["la"])(a0,a1,a2);var _nisps_engine_process_block=Module["_nisps_engine_process_block"]=(a0,a1,a2,a3,a4,a5)=>(_nisps_engine_process_block=Module["_nisps_engine_process_block"]=wasmExports["ma"])(a0,a1,a2,a3,a4,a5);var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["oa"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["pa"])(a0);var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["qa"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["ra"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["sa"])();Module["ccall"]=ccall;Module["cwrap"]=cwrap;var calledRun;var calledPrerun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}if(!calledPrerun){calledPrerun=1;preRun();if(runDependencies>0){return}}function doRun(){if(calledRun)return;calledRun=1;Module["calledRun"]=1;if(ABORT)return;initRuntime();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run();moduleRtn=readyPromise; return moduleRtn; diff --git a/manifold/public/nisps.wasm b/manifold/public/nisps.wasm index 9eb04a87f08e9e7d4a4978b86579f109f31a5c3d..31cacfd21f76c716082204bbc88229aecde0d098 100755 GIT binary patch delta 4036 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 delta 3855 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 { - return this.iml.trainAsync(this.learningRate); + return this.iml.trainAsync(this.learningRate, this.maxIterations); } randomise(spread = this.spread_): void { diff --git a/manifold/src/engine/types.ts b/manifold/src/engine/types.ts index ea180c0..6a3b34e 100644 --- a/manifold/src/engine/types.ts +++ b/manifold/src/engine/types.ts @@ -45,6 +45,9 @@ export interface NispsModule { // ML training. _nisps_ml_add_example(ml: number, features_ptr: number, labels_ptr: number): void; _nisps_ml_train(ml: number, lr: number, max_iter: number, min_err: number, sample_weights_ptr: number): number; + // Persist a new training-hyperparameter default on the handle (S26) — mirrors + // nisps::ml::MLPCore::set_train_config. Does not train. + _nisps_ml_set_train_config(ml: number, lr: number, max_iter: number, min_err: number): void; _nisps_ml_eval_loss(ml: number): number; // ML examples. diff --git a/manifold/src/engine/wasm-iml.ts b/manifold/src/engine/wasm-iml.ts index df46160..887b364 100644 --- a/manifold/src/engine/wasm-iml.ts +++ b/manifold/src/engine/wasm-iml.ts @@ -19,6 +19,7 @@ */ import { Dataset } from './dataset'; +import { ML_TRAIN_DEFAULTS } from '../modes/generated/ml_defaults'; import { anchorModeToInt, momentumModeToInt, @@ -180,6 +181,13 @@ export class WasmIML { dataset!: Dataset; private readonly sink: EngineSink; private lastLoss_: number | null = null; + // JS-side mirror of the training-hyperparameter default, seeded from the + // ONE generated constant (S26, docs/specs/recon/simplification-audit-2026-07 + // .md) rather than hardcoded literals. `setTrainConfig` updates this AND the + // WASM handle's own copy (nisps_ml_set_train_config) so train()/trainAsync() + // fall back to a genuinely runtime-configurable default, not just a JS + // literal. + private trainConfig = { ...ML_TRAIN_DEFAULTS }; private trainer: WasmTrainer | null = null; private storageKey: string; private saveTimer: number | null = null; @@ -620,7 +628,22 @@ export class WasmIML { this.module._nisps_ml_add_example(this.mlHandle, this.featuresBuf.ptr, this.labelsBuf.ptr); } - train(lr = 1.0, maxIter = 1000, minErr = 0.001, sampleWeights?: Float32Array): number { + /** Persist a new training-hyperparameter default (S26): updates the JS-side + * mirror used as the train()/trainAsync() fallback AND the WASM handle's + * own copy via the C API, so the underlying MLP is genuinely + * runtime-configurable rather than just remembering a number to pass on + * each call. */ + setTrainConfig(lr: number, maxIter: number, minErr: number): void { + this.trainConfig = { learningRate: lr, maxIterations: maxIter, minError: minErr }; + this.module._nisps_ml_set_train_config(this.mlHandle, lr, maxIter, minErr); + } + + train( + lr = this.trainConfig.learningRate, + maxIter = this.trainConfig.maxIterations, + minErr = this.trainConfig.minError, + sampleWeights?: Float32Array, + ): number { if (this.dataset.isEmpty()) { this.lastLoss_ = 0; this.sink.setState({ lastLoss: 0 }); @@ -653,7 +676,12 @@ export class WasmIML { return loss; } - async trainAsync(lr = 1.0, maxIter = 1000, minErr = 0.001, sampleWeights?: Float32Array): Promise { + async trainAsync( + lr = this.trainConfig.learningRate, + maxIter = this.trainConfig.maxIterations, + minErr = this.trainConfig.minError, + sampleWeights?: Float32Array, + ): Promise { if (this.dataset.isEmpty()) { this.lastLoss_ = 0; return 0; diff --git a/manifold/src/modes/generated/breakor_schema.ts b/manifold/src/modes/generated/breakor_schema.ts index 0bfe8ab..e719246 100644 --- a/manifold/src/modes/generated/breakor_schema.ts +++ b/manifold/src/modes/generated/breakor_schema.ts @@ -78,8 +78,6 @@ export const BreakorSchema: ModeSchema = { ], output_size: 56, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/channel_strip_schema.ts b/manifold/src/modes/generated/channel_strip_schema.ts index 8bf61c8..e2791a3 100644 --- a/manifold/src/modes/generated/channel_strip_schema.ts +++ b/manifold/src/modes/generated/channel_strip_schema.ts @@ -46,8 +46,6 @@ export const ChannelStripSchema: ModeSchema = { ], output_size: 24, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/elysiamorf_schema.ts b/manifold/src/modes/generated/elysiamorf_schema.ts index b08ec88..a66ebb9 100644 --- a/manifold/src/modes/generated/elysiamorf_schema.ts +++ b/manifold/src/modes/generated/elysiamorf_schema.ts @@ -62,8 +62,6 @@ export const ElysiamorfSchema: ModeSchema = { ], output_size: 40, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/memlcelium_schema.ts b/manifold/src/modes/generated/memlcelium_schema.ts index 2f0f6d9..39c573f 100644 --- a/manifold/src/modes/generated/memlcelium_schema.ts +++ b/manifold/src/modes/generated/memlcelium_schema.ts @@ -78,8 +78,6 @@ export const MemlceliumSchema: ModeSchema = { ], output_size: 56, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/ml_defaults.ts b/manifold/src/modes/generated/ml_defaults.ts new file mode 100644 index 0000000..d1f721d --- /dev/null +++ b/manifold/src/modes/generated/ml_defaults.ts @@ -0,0 +1,17 @@ +// AUTOGENERATED (TS) — do not edit. Source: schemas/ml_defaults.json. Run `bun run codegen/generate.ts` to regenerate. +// The ONE global training-hyperparameter default, shared by every mode on +// every platform — see docs/specs/recon/simplification-audit-2026-07.md S26. +// Consumed by WasmIML's train()/trainAsync() default parameters and +// EngineApi's learningRate/maxIterations options (manifold/src/engine/). + +export interface MlTrainDefaults { + readonly learningRate: number; + readonly maxIterations: number; + readonly minError: number; +} + +export const ML_TRAIN_DEFAULTS: MlTrainDefaults = { + learningRate: 1, + maxIterations: 1000, + minError: 0.001, +}; diff --git a/manifold/src/modes/generated/paf_synth_schema.ts b/manifold/src/modes/generated/paf_synth_schema.ts index 6b66bc0..5890052 100644 --- a/manifold/src/modes/generated/paf_synth_schema.ts +++ b/manifold/src/modes/generated/paf_synth_schema.ts @@ -55,8 +55,6 @@ export const PafSynthSchema: ModeSchema = { ], output_size: 33, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/slp_workshop_schema.ts b/manifold/src/modes/generated/slp_workshop_schema.ts index 4a74ad1..9ced1e1 100644 --- a/manifold/src/modes/generated/slp_workshop_schema.ts +++ b/manifold/src/modes/generated/slp_workshop_schema.ts @@ -78,8 +78,6 @@ export const SlpWorkshopSchema: ModeSchema = { ], output_size: 56, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/sound_analysis_midi_schema.ts b/manifold/src/modes/generated/sound_analysis_midi_schema.ts index 67bd6cc..d40ea06 100644 --- a/manifold/src/modes/generated/sound_analysis_midi_schema.ts +++ b/manifold/src/modes/generated/sound_analysis_midi_schema.ts @@ -36,8 +36,6 @@ export const SoundAnalysisMidiSchema: ModeSchema = { ], output_size: 8, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/types.ts b/manifold/src/modes/generated/types.ts index 1aec060..e095a7e 100644 --- a/manifold/src/modes/generated/types.ts +++ b/manifold/src/modes/generated/types.ts @@ -34,8 +34,6 @@ export interface MLConfig { readonly hidden_layers: readonly number[]; readonly output_size: number; readonly default_spread: number; - readonly default_learning_rate: number; - readonly default_max_iterations: number; } export interface UIConfig { diff --git a/manifold/src/modes/generated/verb_fx_schema.ts b/manifold/src/modes/generated/verb_fx_schema.ts index e24a80e..fae4bd3 100644 --- a/manifold/src/modes/generated/verb_fx_schema.ts +++ b/manifold/src/modes/generated/verb_fx_schema.ts @@ -69,8 +69,6 @@ export const VerbFxSchema: ModeSchema = { ], output_size: 47, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/manifold/src/modes/generated/xiasri_schema.ts b/manifold/src/modes/generated/xiasri_schema.ts index e1b774a..1ebd04e 100644 --- a/manifold/src/modes/generated/xiasri_schema.ts +++ b/manifold/src/modes/generated/xiasri_schema.ts @@ -46,8 +46,6 @@ export const XiasriSchema: ModeSchema = { ], output_size: 24, default_spread: 0.6, - default_learning_rate: 1, - default_max_iterations: 1000, }, params: [ { diff --git a/nisps/ml/generated/ml_defaults.hpp b/nisps/ml/generated/ml_defaults.hpp new file mode 100644 index 0000000..f07cd24 --- /dev/null +++ b/nisps/ml/generated/ml_defaults.hpp @@ -0,0 +1,29 @@ +// AUTOGENERATED (C++) — do not edit. Source: schemas/ml_defaults.json. Run `bun run codegen/generate.ts` to regenerate. +// The ONE global training-hyperparameter default, shared by every mode on +// every platform (firmware/WASM/VCV) — see docs/specs/recon/ +// simplification-audit-2026-07.md S26. Consumed by +// nisps::ml::MLPCore::TrainConfig's default member initialisers +// (nisps/ml/mlp.hpp); nisps_ml_set_train_config() and +// nisps::ml::MLPCore::set_train_config() make it runtime-overridable. +#ifndef NISPS_ML_GENERATED_ML_DEFAULTS_HPP +#define NISPS_ML_GENERATED_ML_DEFAULTS_HPP + +#include + +namespace nisps::ml::generated { + +struct MlTrainDefaults { + float learning_rate; + std::size_t max_iterations; + float min_error; +}; + +inline constexpr MlTrainDefaults kMlTrainDefaults = { + 1.0f, + 1000u, + 0.001f, +}; + +} // namespace nisps::ml::generated + +#endif // NISPS_ML_GENERATED_ML_DEFAULTS_HPP diff --git a/nisps/ml/mlp.hpp b/nisps/ml/mlp.hpp index 030e8a2..245f36a 100644 --- a/nisps/ml/mlp.hpp +++ b/nisps/ml/mlp.hpp @@ -48,6 +48,7 @@ #include "../core/concepts.hpp" #include "../core/perf.hpp" #include "../core/rng.hpp" +#include "generated/ml_defaults.hpp" #include "activations.hpp" #include "init.hpp" #include "loss.hpp" @@ -58,6 +59,30 @@ namespace nisps::ml { +// Per-instance training-hyperparameter config (S26, docs/specs/recon/ +// simplification-audit-2026-07.md): the ONE learning_rate/max_iterations/ +// min_error default used to be duplicated identically across all nine +// schemas/modes/*.json (unread at runtime), hardcoded again in this file's +// no-arg train() overload, again in manifold's wasm-iml.ts TS default +// parameters, and a FOURTH time (diverging: 0.1/200/0.00001) in vcv/src/ +// iml.hpp. Default member initialisers below pull the single generated +// constant (schemas/ml_defaults.json -> nisps/ml/generated/ml_defaults.hpp) +// so every MLPCore instance — firmware, WASM handle, VCV adapter — starts +// pre-configured identically; `set_train_config` makes it runtime-overridable, +// same as the codebase-wide decision requires. +// +// Note on layering: ml_defaults.hpp is generated into nisps/ml/generated/, NOT +// alongside schema_types.hpp in nisps/modes/generated/ where the rest of the +// codegen output lives. Training hyperparameters are an ML fact, not a mode +// fact, and nisps/ml sits below nisps/modes — emitting them there would make +// this file include upward. The TS side has no equivalent layering to respect +// and keeps all generated output in one directory. +struct TrainConfig { + float learning_rate = ::nisps::ml::generated::kMlTrainDefaults.learning_rate; + std::size_t max_iterations = ::nisps::ml::generated::kMlTrainDefaults.max_iterations; + float min_error = ::nisps::ml::generated::kMlTrainDefaults.min_error; +}; + // Activation of layer L in the fixed 4-layer topology. template inline constexpr Activation kLayerActivation = @@ -139,11 +164,24 @@ class MLPCore : public Storage { for (std::size_t i = 0; i < n_out; ++i) dsl[l_off + i] = labels[i]; } - // Concept-required no-arg overload. + // Concept-required no-arg overload. Reads the runtime-configurable + // `train_config_` (default-initialised from the single generated default; + // see `TrainConfig` above) rather than hardcoding numbers here. float train() noexcept { - return train(1.f, 1000u, 0.001f, std::span{}); + return train(train_config_.learning_rate, train_config_.max_iterations, + train_config_.min_error, std::span{}); } + // Runtime knob for the no-arg train() overload (S26). Does not affect the + // explicit-argument train() below, which stays the always-available + // explicit path. + void set_train_config(float lr, std::size_t max_iter, float min_err) noexcept { + train_config_.learning_rate = lr; + train_config_.max_iterations = max_iter; + train_config_.min_error = min_err; + } + const TrainConfig& train_config() const noexcept { return train_config_; } + // Full SGD training. `sample_weights`, if non-empty, must size to the // current example count and sum to 1.0 (caller's responsibility — we // do NOT renormalize). @@ -556,6 +594,7 @@ class MLPCore : public Storage { std::size_t dataset_count_ = 0u; std::size_t dataset_head_ = 0u; std::size_t loss_history_count_ = 0u; + TrainConfig train_config_{}; Rng rng_; }; diff --git a/nisps/modes/external_synth_midi.hpp b/nisps/modes/external_synth_midi.hpp index bcd3555..4fcdd7a 100644 --- a/nisps/modes/external_synth_midi.hpp +++ b/nisps/modes/external_synth_midi.hpp @@ -57,8 +57,12 @@ namespace nisps::modes { // instantiation (see the file-header comment for why these are hand-named // rather than codegen'd): 4 joystick inputs -> [10,14,18] hidden -> NOut // (device-CC-count-driven) outputs, matching every other 4-joystick-input -// mode's schema defaults (default_spread 0.6, default_learning_rate 1.0, -// default_max_iterations 1000). +// mode's schema default_spread (0.6). The training hyperparameter defaults +// (learning_rate/max_iterations/min_error) are no longer part of +// `ParamSchema` at all (S26) — they live once, globally, in +// `nisps::ml::generated::kMlTrainDefaults` (nisps/ml/generated/ +// ml_defaults.hpp) and are wired via `nisps::ml::MLPCore::TrainConfig`'s +// default member initialisers instead. namespace ext_synth_defaults { inline constexpr std::size_t kInputSize = 4u; inline constexpr std::array kInputChannels{ @@ -66,8 +70,6 @@ inline constexpr std::array kInputChannels{ std::string_view{"joy_z"}, std::string_view{"joy_w"}}; inline constexpr std::array kHiddenLayers{10u, 14u, 18u}; inline constexpr float kDefaultSpread = 0.6f; -inline constexpr float kDefaultLearningRate = 1.0f; -inline constexpr std::size_t kDefaultMaxIterations = 1000u; } // namespace ext_synth_defaults // The net-shape alias every instantiation uses (mirrors S6/S25's per-mode @@ -185,8 +187,6 @@ class ExternalSynthMIDIMode : public ModeBase< std::span(ext_synth_defaults::kHiddenLayers), NOut, ext_synth_defaults::kDefaultSpread, - ext_synth_defaults::kDefaultLearningRate, - ext_synth_defaults::kDefaultMaxIterations, std::span(kNoParams), std::span(kNoVoiceSpaces), kUI, diff --git a/nisps/modes/generated/breakor_schema.hpp b/nisps/modes/generated/breakor_schema.hpp index 60bcfd0..444dea1 100644 --- a/nisps/modes/generated/breakor_schema.hpp +++ b/nisps/modes/generated/breakor_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kBreakorMLConfig = { 4u, 56u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kBreakorParamCount = 56u; @@ -558,8 +556,6 @@ inline constexpr ::nisps::ParamSchema kBreakorSchema = { std::span(kBreakorHiddenLayers), kBreakorMLConfig.output_size, kBreakorMLConfig.default_spread, - kBreakorMLConfig.default_learning_rate, - kBreakorMLConfig.default_max_iterations, std::span(kBreakorParams), std::span(kBreakorVoiceSpaces), kBreakorUI, diff --git a/nisps/modes/generated/channel_strip_schema.hpp b/nisps/modes/generated/channel_strip_schema.hpp index 82cc6c8..57ca4c2 100644 --- a/nisps/modes/generated/channel_strip_schema.hpp +++ b/nisps/modes/generated/channel_strip_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kChannelStripMLConfig = { 4u, 24u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kChannelStripParamCount = 24u; @@ -277,8 +275,6 @@ inline constexpr ::nisps::ParamSchema kChannelStripSchema = { std::span(kChannelStripHiddenLayers), kChannelStripMLConfig.output_size, kChannelStripMLConfig.default_spread, - kChannelStripMLConfig.default_learning_rate, - kChannelStripMLConfig.default_max_iterations, std::span(kChannelStripParams), std::span(kChannelStripVoiceSpaces), kChannelStripUI, diff --git a/nisps/modes/generated/elysiamorf_schema.hpp b/nisps/modes/generated/elysiamorf_schema.hpp index 202c490..1e1a1e9 100644 --- a/nisps/modes/generated/elysiamorf_schema.hpp +++ b/nisps/modes/generated/elysiamorf_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kElysiamorfMLConfig = { 4u, 40u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kElysiamorfParamCount = 40u; @@ -414,8 +412,6 @@ inline constexpr ::nisps::ParamSchema kElysiamorfSchema = { std::span(kElysiamorfHiddenLayers), kElysiamorfMLConfig.output_size, kElysiamorfMLConfig.default_spread, - kElysiamorfMLConfig.default_learning_rate, - kElysiamorfMLConfig.default_max_iterations, std::span(kElysiamorfParams), std::span(kElysiamorfVoiceSpaces), kElysiamorfUI, diff --git a/nisps/modes/generated/memlcelium_schema.hpp b/nisps/modes/generated/memlcelium_schema.hpp index d478c68..c232a15 100644 --- a/nisps/modes/generated/memlcelium_schema.hpp +++ b/nisps/modes/generated/memlcelium_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kMemlceliumMLConfig = { 4u, 56u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kMemlceliumParamCount = 56u; @@ -560,8 +558,6 @@ inline constexpr ::nisps::ParamSchema kMemlceliumSchema = { std::span(kMemlceliumHiddenLayers), kMemlceliumMLConfig.output_size, kMemlceliumMLConfig.default_spread, - kMemlceliumMLConfig.default_learning_rate, - kMemlceliumMLConfig.default_max_iterations, std::span(kMemlceliumParams), std::span(kMemlceliumVoiceSpaces), kMemlceliumUI, diff --git a/nisps/modes/generated/paf_synth_schema.hpp b/nisps/modes/generated/paf_synth_schema.hpp index 197c671..a202a12 100644 --- a/nisps/modes/generated/paf_synth_schema.hpp +++ b/nisps/modes/generated/paf_synth_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kPafSynthMLConfig = { 4u, 33u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kPafSynthParamCount = 33u; @@ -359,8 +357,6 @@ inline constexpr ::nisps::ParamSchema kPafSynthSchema = { std::span(kPafSynthHiddenLayers), kPafSynthMLConfig.output_size, kPafSynthMLConfig.default_spread, - kPafSynthMLConfig.default_learning_rate, - kPafSynthMLConfig.default_max_iterations, std::span(kPafSynthParams), std::span(kPafSynthVoiceSpaces), kPafSynthUI, diff --git a/nisps/modes/generated/schema_types.hpp b/nisps/modes/generated/schema_types.hpp index a4f5371..1dbe2c0 100644 --- a/nisps/modes/generated/schema_types.hpp +++ b/nisps/modes/generated/schema_types.hpp @@ -37,8 +37,6 @@ struct MLConfig { std::size_t input_size; std::size_t output_size; float default_spread; - float default_learning_rate; - std::size_t default_max_iterations; }; enum class PrimaryInput : unsigned char { @@ -73,8 +71,6 @@ struct ParamSchema { std::span hidden_layers; std::size_t output_size; float default_spread; - float default_learning_rate; - std::size_t default_max_iterations; std::span params; std::span voice_spaces; ::nisps::modes::generated::UIConfig ui; diff --git a/nisps/modes/generated/slp_workshop_schema.hpp b/nisps/modes/generated/slp_workshop_schema.hpp index f5c938d..941c9c3 100644 --- a/nisps/modes/generated/slp_workshop_schema.hpp +++ b/nisps/modes/generated/slp_workshop_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kSlpWorkshopMLConfig = { 4u, 56u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kSlpWorkshopParamCount = 56u; @@ -560,8 +558,6 @@ inline constexpr ::nisps::ParamSchema kSlpWorkshopSchema = { std::span(kSlpWorkshopHiddenLayers), kSlpWorkshopMLConfig.output_size, kSlpWorkshopMLConfig.default_spread, - kSlpWorkshopMLConfig.default_learning_rate, - kSlpWorkshopMLConfig.default_max_iterations, std::span(kSlpWorkshopParams), std::span(kSlpWorkshopVoiceSpaces), kSlpWorkshopUI, diff --git a/nisps/modes/generated/sound_analysis_midi_schema.hpp b/nisps/modes/generated/sound_analysis_midi_schema.hpp index 2b9023d..44b62dc 100644 --- a/nisps/modes/generated/sound_analysis_midi_schema.hpp +++ b/nisps/modes/generated/sound_analysis_midi_schema.hpp @@ -33,8 +33,6 @@ inline constexpr MLConfig kSoundAnalysisMidiMLConfig = { 10u, 8u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kSoundAnalysisMidiParamCount = 8u; @@ -132,8 +130,6 @@ inline constexpr ::nisps::ParamSchema kSoundAnalysisMidiSchema = { std::span(kSoundAnalysisMidiHiddenLayers), kSoundAnalysisMidiMLConfig.output_size, kSoundAnalysisMidiMLConfig.default_spread, - kSoundAnalysisMidiMLConfig.default_learning_rate, - kSoundAnalysisMidiMLConfig.default_max_iterations, std::span(kSoundAnalysisMidiParams), std::span(kSoundAnalysisMidiVoiceSpaces), kSoundAnalysisMidiUI, diff --git a/nisps/modes/generated/verb_fx_schema.hpp b/nisps/modes/generated/verb_fx_schema.hpp index 7ce2076..6604ea6 100644 --- a/nisps/modes/generated/verb_fx_schema.hpp +++ b/nisps/modes/generated/verb_fx_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kVerbFxMLConfig = { 4u, 47u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kVerbFxParamCount = 47u; @@ -490,8 +488,6 @@ inline constexpr ::nisps::ParamSchema kVerbFxSchema = { std::span(kVerbFxHiddenLayers), kVerbFxMLConfig.output_size, kVerbFxMLConfig.default_spread, - kVerbFxMLConfig.default_learning_rate, - kVerbFxMLConfig.default_max_iterations, std::span(kVerbFxParams), std::span(kVerbFxVoiceSpaces), kVerbFxUI, diff --git a/nisps/modes/generated/xiasri_schema.hpp b/nisps/modes/generated/xiasri_schema.hpp index b0942c0..d300045 100644 --- a/nisps/modes/generated/xiasri_schema.hpp +++ b/nisps/modes/generated/xiasri_schema.hpp @@ -27,8 +27,6 @@ inline constexpr MLConfig kXiasriMLConfig = { 4u, 24u, 0.6f, - 1.0f, - 1000u, }; inline constexpr std::size_t kXiasriParamCount = 24u; @@ -272,8 +270,6 @@ inline constexpr ::nisps::ParamSchema kXiasriSchema = { std::span(kXiasriHiddenLayers), kXiasriMLConfig.output_size, kXiasriMLConfig.default_spread, - kXiasriMLConfig.default_learning_rate, - kXiasriMLConfig.default_max_iterations, std::span(kXiasriParams), std::span(kXiasriVoiceSpaces), kXiasriUI, diff --git a/nisps/wasm/bindings.cpp b/nisps/wasm/bindings.cpp index 814837d..379293a 100644 --- a/nisps/wasm/bindings.cpp +++ b/nisps/wasm/bindings.cpp @@ -502,6 +502,20 @@ float nisps_ml_train(void* ml, float lr, int max_iter, float min_err, return h->mlp.train(lr, static_cast(max_iter), min_err, weights); } +// Persist a new training-hyperparameter default on the handle itself (S26): +// mirrors nisps::ml::MLPCore::set_train_config so the browser MLP is +// genuinely runtime-configurable, not just JS remembering a number to pass on +// each nisps_ml_train() call. Does not train; only reconfigures the no-arg +// train() fallback (unused WASM-side today, but keeps the handle's own state +// consistent with firmware/VCV, which carry the same knob). +EMSCRIPTEN_KEEPALIVE +void nisps_ml_set_train_config(void* ml, float lr, int max_iter, float min_err) { + if (!ml) return; + auto* h = static_cast(ml); + if (max_iter <= 0) max_iter = 1; + h->mlp.set_train_config(lr, static_cast(max_iter), min_err); +} + EMSCRIPTEN_KEEPALIVE float nisps_ml_eval_loss(void* ml) { if (!ml) return 0.f; diff --git a/schemas/ml_defaults.json b/schemas/ml_defaults.json new file mode 100644 index 0000000..8405d1e --- /dev/null +++ b/schemas/ml_defaults.json @@ -0,0 +1,7 @@ +{ + "$schema": "ml_defaults.schema.json", + "_note": "The ONE default learning rate / max iterations / min-error for training, shared by every mode on every platform (audit S26, docs/specs/recon/simplification-audit-2026-07.md). Values preserve the numbers previously hardcoded in nisps/ml/mlp.hpp's no-arg train() and manifold/src/engine/wasm-iml.ts's TS default parameters, so wiring this up is numerically a no-op for firmware and WASM. It is NOT a no-op for vcv/src/iml.hpp, whose own private defaults (200 / 0.1 / 0.00001) diverged and have been deleted in the same change (see vcv/src/iml.hpp's IML constructor comment) — a real behaviour change to the VCV module.", + "learning_rate": 1.0, + "max_iterations": 1000, + "min_error": 0.001 +} diff --git a/schemas/ml_defaults.schema.json b/schemas/ml_defaults.schema.json new file mode 100644 index 0000000..5ecd115 --- /dev/null +++ b/schemas/ml_defaults.schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://memlnaut/schemas/ml_defaults.schema.json", + "title": "MEMLNaut ML Training Defaults", + "description": "Single, global declaration of the MLP training-hyperparameter defaults (learning rate, max iterations, min-error/convergence threshold) — ONE value per field, shared by every mode on every platform (firmware, WASM/manifold, VCV). This is only the DEFAULT: codegen/generate.ts emits it to nisps/modes/generated/ml_defaults.hpp (C++) and manifold/src/modes/generated/ml_defaults.ts (TS), and nisps::ml::MLPCore::set_train_config()/train_config() (nisps/ml/mlp.hpp) makes it overridable at runtime on every target. Per-mode ml.default_spread stays separate — it is genuinely per-mode-tuned, unlike these.", + "type": "object", + "required": ["learning_rate", "max_iterations", "min_error"], + "additionalProperties": false, + "properties": { + "$schema": { "type": "string" }, + "_note": { + "type": "string", + "description": "Free-text provenance note from the schema author." + }, + "learning_rate": { + "type": "number", + "exclusiveMinimum": 0.0, + "description": "SGD learning rate the no-arg train() falls back to." + }, + "max_iterations": { + "type": "integer", + "minimum": 1, + "description": "Epoch cap for the no-arg train() fallback." + }, + "min_error": { + "type": "number", + "minimum": 0.0, + "description": "Early-stop threshold: training stops once epoch loss drops below this value." + } + } +} diff --git a/schemas/modes/breakor.json b/schemas/modes/breakor.json index 7b569b1..983ec93 100644 --- a/schemas/modes/breakor.json +++ b/schemas/modes/breakor.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 14, 18], "output_size": 56, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "kick_ratio0", "label": "Kick Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "kick" }, diff --git a/schemas/modes/channel_strip.json b/schemas/modes/channel_strip.json index 822c5d3..fb87164 100644 --- a/schemas/modes/channel_strip.json +++ b/schemas/modes/channel_strip.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 10, 14], "output_size": 24, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "pre_gain", "label": "Pre Gain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "square", "group": "gain" }, diff --git a/schemas/modes/elysiamorf.json b/schemas/modes/elysiamorf.json index 25ba5b9..a395c05 100644 --- a/schemas/modes/elysiamorf.json +++ b/schemas/modes/elysiamorf.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 14, 18], "output_size": 40, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "fm0_carrier", "label": "FM0 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm0" }, diff --git a/schemas/modes/memlcelium.json b/schemas/modes/memlcelium.json index aa1666c..194f9cb 100644 --- a/schemas/modes/memlcelium.json +++ b/schemas/modes/memlcelium.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 14, 18], "output_size": 56, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "seq0_ratio0", "label": "Seq0 Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, diff --git a/schemas/modes/paf_synth.json b/schemas/modes/paf_synth.json index dd41712..57f33a4 100644 --- a/schemas/modes/paf_synth.json +++ b/schemas/modes/paf_synth.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 10, 14], "output_size": 33, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "p00", "label": "Param 00", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, diff --git a/schemas/modes/slp_workshop.json b/schemas/modes/slp_workshop.json index e1ce169..e63a7a4 100644 --- a/schemas/modes/slp_workshop.json +++ b/schemas/modes/slp_workshop.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 14, 18], "output_size": 56, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "seq0_ratio0", "label": "Seq0 Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, diff --git a/schemas/modes/sound_analysis_midi.json b/schemas/modes/sound_analysis_midi.json index 0e0ae07..0d71dbb 100644 --- a/schemas/modes/sound_analysis_midi.json +++ b/schemas/modes/sound_analysis_midi.json @@ -19,9 +19,7 @@ "input_size": 10, "hidden_layers": [10, 10, 14], "output_size": 8, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "midi_cc0", "label": "MIDI CC 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, diff --git a/schemas/modes/verb_fx.json b/schemas/modes/verb_fx.json index bb908f4..07a1f3a 100644 --- a/schemas/modes/verb_fx.json +++ b/schemas/modes/verb_fx.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 14, 18], "output_size": 47, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "fb_delay_xfade", "label": "Bank/Delay XFade", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "routing" }, diff --git a/schemas/modes/xiasri.json b/schemas/modes/xiasri.json index 57678a5..45008b3 100644 --- a/schemas/modes/xiasri.json +++ b/schemas/modes/xiasri.json @@ -8,9 +8,7 @@ "input_size": 4, "hidden_layers": [10, 10, 14], "output_size": 24, - "default_spread": 0.6, - "default_learning_rate": 1.0, - "default_max_iterations": 1000 + "default_spread": 0.6 }, "params": [ { "name": "dl1_mix", "label": "Delay 1 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, diff --git a/schemas/schema.json b/schemas/schema.json index ed69eef..f5ed170 100644 --- a/schemas/schema.json +++ b/schemas/schema.json @@ -36,9 +36,7 @@ "input_size", "hidden_layers", "output_size", - "default_spread", - "default_learning_rate", - "default_max_iterations" + "default_spread" ], "additionalProperties": false, "properties": { @@ -58,9 +56,7 @@ "minItems": 1 }, "output_size": { "type": "integer", "minimum": 1 }, - "default_spread": { "type": "number", "minimum": 0.0, "maximum": 1.0 }, - "default_learning_rate": { "type": "number", "exclusiveMinimum": 0.0 }, - "default_max_iterations": { "type": "integer", "minimum": 1 } + "default_spread": { "type": "number", "minimum": 0.0, "maximum": 1.0 } } }, "params": { diff --git a/scripts/build-wasm.sh b/scripts/build-wasm.sh index a4448ab..7472bdb 100755 --- a/scripts/build-wasm.sh +++ b/scripts/build-wasm.sh @@ -41,7 +41,7 @@ EXPORTED_FUNCS='[ "_malloc","_free", "_nisps_ml_create","_nisps_ml_destroy","_nisps_ml_reshape", "_nisps_ml_set_input","_nisps_ml_process","_nisps_ml_outputs","_nisps_ml_infer_batch", - "_nisps_ml_add_example","_nisps_ml_train","_nisps_ml_eval_loss", + "_nisps_ml_add_example","_nisps_ml_train","_nisps_ml_set_train_config","_nisps_ml_eval_loss", "_nisps_ml_clear_examples", "_nisps_ml_weight_count","_nisps_ml_get_weights","_nisps_ml_set_weights", "_nisps_ml_draw_weights", diff --git a/vcv/src/iml.hpp b/vcv/src/iml.hpp index 41479e0..8b4378d 100644 --- a/vcv/src/iml.hpp +++ b/vcv/src/iml.hpp @@ -45,6 +45,7 @@ #include "../../nisps/core/rng.hpp" #include "../../nisps/ml/dynamic_storage.hpp" #include "../../nisps/ml/mlp.hpp" +#include "../../nisps/ml/generated/ml_defaults.hpp" namespace nisps { @@ -77,11 +78,23 @@ class IML { // are unchanged. `hidden` MUST carry exactly three sizes (the core topology // is fixed at three hidden layers); fewer are padded from the default, // extras ignored. + // BEHAVIOUR CHANGE (S26, docs/specs/recon/simplification-audit-2026-07.md): + // these three defaults used to be private to this adapter (200 / 0.1 / + // 0.00001) and disagreed with the firmware/WASM default (1000 / 1.0 / + // 0.001) that every other target already used. They now come from the + // ONE shared generated constant (schemas/ml_defaults.json -> + // nisps::ml::generated::kMlTrainDefaults) instead of a private copy. + // `MEMLNaut.cpp` constructs `IML` with only 3 positional args, so this is + // a REAL runtime behaviour change for the module: 5x more max iterations, + // 10x the learning rate, and a 100x looser (larger) early-stop threshold. explicit IML(std::size_t n_inputs, std::size_t n_outputs, std::vector hidden = {16u, 24u, 16u}, - std::size_t max_iterations = 200u, - Float learning_rate = static_cast(0.1), - Float convergence_threshold = static_cast(0.00001), + std::size_t max_iterations = + ::nisps::ml::generated::kMlTrainDefaults.max_iterations, + Float learning_rate = static_cast( + ::nisps::ml::generated::kMlTrainDefaults.learning_rate), + Float convergence_threshold = static_cast( + ::nisps::ml::generated::kMlTrainDefaults.min_error), std::uint64_t seed = 0xC0FFEEu) : n_inputs_(n_inputs), n_outputs_(n_outputs),