refactor(wasm): delete 12 dead C-API entries and the weights-publish channel
Phase 1 group 4 (S33, S34, L54).
- S33: removed 12 dead entries across the full 5-layer registration chain
(bindings.cpp KEEPALIVE -> EXPORTED_FUNCTIONS -> the NispsModule declaration
table -> the WasmIML wrapper -> the EngineApi facade): nisps_ml_reset,
example_count, move_weights, feedback_learning_paused, feedback_drag,
jolt_lr_scale, jolt_tick_lr_ramp, pipeline_state_size/save_state/load_state,
feedback_placing and feedback_state. Each was grepped against manifold/src,
manifold/tests, the e2e specs, manifold/tests/wasm-load.ts and
tests/cpp/parity_wasm.mjs — the parity gate builds its own API via cwrap and
is a real consumer, so it counts.
KEPT deliberately: EXPORTED_RUNTIME's heap views + ccall/cwrap (the parity
harness and wasm-load.ts depend on them), and nisps_ml_feedback_static_output,
whose C export IS called directly by parity_wasm.mjs even though no TS
wrapper reaches it. Also dropped parity_wasm.mjs's moveWeights cwrap, which
was declared but never invoked.
- S34: deleted the publishWeights_ channel — EngineSink.setWeights,
Spine.setWeights/weights()/liveWeights and every call site. It ran a C->heap
copy plus a fresh Float32Array allocation at up to 200 Hz into a field
nothing read. getWeights survives for persistence and the debug probe.
- L54: worklet loader — deleted the unused imports object, the 'c' branch,
exMap and the duplicate second loop, and replaced the silent `() => 0` stub
with one that throws, so a missing import fails loudly instead of returning
plausible zeros into the audio path.
manifold/public/nisps.{js,wasm} rebuilt with the trimmed export list (emcc
3.1.69, the CI-pinned version) and committed — the freshness gate added in
Phase 0 requires it, and the webhook ships this artifact to production.
Gates: run-all-tests.sh ALL GREEN, parity 1273 floats within 1e-5.
This commit is contained in:
parent
ea588e79cd
commit
c98d25c255
12 changed files with 33 additions and 267 deletions
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -26,16 +26,12 @@ export interface EngineFeedbackApi {
|
||||||
thumbsUp(): number;
|
thumbsUp(): number;
|
||||||
/** Negative feedback (thumbs-down). Returns the FeedbackAction int. */
|
/** Negative feedback (thumbs-down). Returns the FeedbackAction int. */
|
||||||
thumbsDown(speed?: number, spread?: number, pinMask?: Uint8Array): number;
|
thumbsDown(speed?: number, spread?: number, pinMask?: Uint8Array): number;
|
||||||
/** Drag (continuous perturbation) tick. */
|
|
||||||
drag(): number;
|
|
||||||
setMode(mode: FeedbackMode): void;
|
setMode(mode: FeedbackMode): void;
|
||||||
getMode(): FeedbackMode;
|
getMode(): FeedbackMode;
|
||||||
/** Restrict feedback to a subset of outputs (solo / column-freeze). */
|
/** Restrict feedback to a subset of outputs (solo / column-freeze). */
|
||||||
setFocus(mask: Uint8Array | null): void;
|
setFocus(mask: Uint8Array | null): void;
|
||||||
/** True while the controller is exploring (perturbed). */
|
/** True while the controller is exploring (perturbed). */
|
||||||
exploring(): boolean;
|
exploring(): boolean;
|
||||||
/** True while the controller has paused learning. */
|
|
||||||
learningPaused(): boolean;
|
|
||||||
|
|
||||||
// ---- ExploreAndPlace lifecycle (shared C++ core; mode 'explore_and_place') --
|
// ---- ExploreAndPlace lifecycle (shared C++ core; mode 'explore_and_place') --
|
||||||
/** Idle→Exploring: snapshot the real net, randomise a scratchpad. */
|
/** Idle→Exploring: snapshot the real net, randomise a scratchpad. */
|
||||||
|
|
@ -54,10 +50,6 @@ export interface EngineFeedbackApi {
|
||||||
commitPlace(): void;
|
commitPlace(): void;
|
||||||
/** Placing→Exploring: back out without storing. */
|
/** Placing→Exploring: back out without storing. */
|
||||||
cancelPlace(): void;
|
cancelPlace(): void;
|
||||||
/** True while Placing (the frozen output is held). */
|
|
||||||
placing(): boolean;
|
|
||||||
/** ExploreState int: 0=Idle 1=Exploring 2=Placing. */
|
|
||||||
exploreState(): number;
|
|
||||||
/** Scratchpad undo-ring depth available to pop. */
|
/** Scratchpad undo-ring depth available to pop. */
|
||||||
undoDepth(): number;
|
undoDepth(): number;
|
||||||
/** The frozen placed / just-committed output (null if none). */
|
/** The frozen placed / just-committed output (null if none). */
|
||||||
|
|
@ -92,9 +84,6 @@ export interface EngineExploreApi {
|
||||||
/** Release: freeze the weights where they landed (permanent). */
|
/** Release: freeze the weights where they landed (permanent). */
|
||||||
joltRelease(): void;
|
joltRelease(): void;
|
||||||
joltActive(): boolean;
|
joltActive(): boolean;
|
||||||
/** Post-release LR-ramp multiplier (0 held → 1 over ~5 s of ticks). */
|
|
||||||
joltLrScale(): number;
|
|
||||||
joltTickLrRamp(): void;
|
|
||||||
/** Exploration amount in [0,1]; 0 disables (inert — parity-safe). */
|
/** Exploration amount in [0,1]; 0 disables (inert — parity-safe). */
|
||||||
setExploreIntensity(level: number): void;
|
setExploreIntensity(level: number): void;
|
||||||
exploreIntensity(): number;
|
exploreIntensity(): number;
|
||||||
|
|
@ -169,12 +158,10 @@ export class EngineApi {
|
||||||
this.spine.routedOutput() ?? this.spine.outputs(),
|
this.spine.routedOutput() ?? this.spine.outputs(),
|
||||||
pinMask,
|
pinMask,
|
||||||
),
|
),
|
||||||
drag: () => this.iml.feedbackDrag(),
|
|
||||||
setMode: (mode) => this.iml.feedbackSetMode(mode),
|
setMode: (mode) => this.iml.feedbackSetMode(mode),
|
||||||
getMode: () => this.iml.feedbackGetMode(),
|
getMode: () => this.iml.feedbackGetMode(),
|
||||||
setFocus: (mask) => this.iml.feedbackSetFocus(mask),
|
setFocus: (mask) => this.iml.feedbackSetFocus(mask),
|
||||||
exploring: () => this.iml.feedbackExploring(),
|
exploring: () => this.iml.feedbackExploring(),
|
||||||
learningPaused: () => this.iml.feedbackLearningPaused(),
|
|
||||||
enterExplore: (spread = this.spread_) => this.iml.feedbackEnterExplore(spread),
|
enterExplore: (spread = this.spread_) => this.iml.feedbackEnterExplore(spread),
|
||||||
exitExplore: () => this.iml.feedbackExitExplore(),
|
exitExplore: () => this.iml.feedbackExitExplore(),
|
||||||
reroll: (spread = this.spread_) => this.iml.feedbackReroll(spread),
|
reroll: (spread = this.spread_) => this.iml.feedbackReroll(spread),
|
||||||
|
|
@ -183,8 +170,6 @@ export class EngineApi {
|
||||||
like: () => this.iml.feedbackLike(),
|
like: () => this.iml.feedbackLike(),
|
||||||
commitPlace: () => this.iml.feedbackCommitPlace(),
|
commitPlace: () => this.iml.feedbackCommitPlace(),
|
||||||
cancelPlace: () => this.iml.feedbackCancelPlace(),
|
cancelPlace: () => this.iml.feedbackCancelPlace(),
|
||||||
placing: () => this.iml.feedbackPlacing(),
|
|
||||||
exploreState: () => this.iml.feedbackState(),
|
|
||||||
undoDepth: () => this.iml.feedbackUndoDepth(),
|
undoDepth: () => this.iml.feedbackUndoDepth(),
|
||||||
placedOutput: () => this.iml.feedbackPlacedOutput(),
|
placedOutput: () => this.iml.feedbackPlacedOutput(),
|
||||||
dislikeGeometric: (heardVec?: Float32Array, lr = 0) =>
|
dislikeGeometric: (heardVec?: Float32Array, lr = 0) =>
|
||||||
|
|
@ -200,8 +185,6 @@ export class EngineApi {
|
||||||
joltStep: () => this.iml.joltStep(),
|
joltStep: () => this.iml.joltStep(),
|
||||||
joltRelease: () => this.iml.joltRelease(),
|
joltRelease: () => this.iml.joltRelease(),
|
||||||
joltActive: () => this.iml.joltActive(),
|
joltActive: () => this.iml.joltActive(),
|
||||||
joltLrScale: () => this.iml.joltLrScale(),
|
|
||||||
joltTickLrRamp: () => this.iml.joltTickLrRamp(),
|
|
||||||
setExploreIntensity: (level) => this.iml.setExploreIntensity(level),
|
setExploreIntensity: (level) => this.iml.setExploreIntensity(level),
|
||||||
exploreIntensity: () => this.iml.exploreIntensity(),
|
exploreIntensity: () => this.iml.exploreIntensity(),
|
||||||
exploreApply: (inout) => this.iml.exploreApply(inout),
|
exploreApply: (inout) => this.iml.exploreApply(inout),
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ export interface EngineSink {
|
||||||
setState(patch: EngineStatePatch): void;
|
setState(patch: EngineStatePatch): void;
|
||||||
/** Publish a fresh output vector (already copied; caller may keep it). */
|
/** Publish a fresh output vector (already copied; caller may keep it). */
|
||||||
setOutputs(out: Float32Array): void;
|
setOutputs(out: Float32Array): void;
|
||||||
/** Publish a fresh flat weight array. */
|
|
||||||
setWeights(w: Float32Array): void;
|
|
||||||
/** Emit a named engine event (`ml.*`, `mode.*`, …) with an optional payload. */
|
/** Emit a named engine event (`ml.*`, `mode.*`, …) with an optional payload. */
|
||||||
emit(event: string, payload?: unknown): void;
|
emit(event: string, payload?: unknown): void;
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +36,5 @@ export interface EngineSink {
|
||||||
export const noopSink: EngineSink = {
|
export const noopSink: EngineSink = {
|
||||||
setState() {},
|
setState() {},
|
||||||
setOutputs() {},
|
setOutputs() {},
|
||||||
setWeights() {},
|
|
||||||
emit() {},
|
emit() {},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@ export interface SpineState {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The spine doubles as the `EngineSink` consumed by `WasmIML`. WasmIML calls
|
* The spine doubles as the `EngineSink` consumed by `WasmIML`. WasmIML calls
|
||||||
* `setState/setOutputs/setWeights/emit`; the spine merges into its state,
|
* `setState/setOutputs/emit`; the spine merges into its state, stashes the
|
||||||
* stashes the live output/weight buffers, and bumps the version counter so
|
* live output buffer, and bumps the version counter so `useSyncExternalStore`
|
||||||
* `useSyncExternalStore` consumers re-read.
|
* consumers re-read.
|
||||||
*/
|
*/
|
||||||
export class Spine implements EngineSink {
|
export class Spine implements EngineSink {
|
||||||
private state_: SpineState = {
|
private state_: SpineState = {
|
||||||
|
|
@ -93,9 +93,8 @@ export class Spine implements EngineSink {
|
||||||
private mlBuf: F32 = new Float32Array(126);
|
private mlBuf: F32 = new Float32Array(126);
|
||||||
private routedBuf: F32 | null = null;
|
private routedBuf: F32 | null = null;
|
||||||
|
|
||||||
// Last live output (post-ML, pre-routing) and weights, read imperatively.
|
// Last live output (post-ML, pre-routing), read imperatively.
|
||||||
private liveOutputs: F32 = new Float32Array(126);
|
private liveOutputs: F32 = new Float32Array(126);
|
||||||
private liveWeights: F32 = new Float32Array(0);
|
|
||||||
|
|
||||||
// Optional post-output transform, applied to the routed buffer AFTER the
|
// Optional post-output transform, applied to the routed buffer AFTER the
|
||||||
// output pipeline and BEFORE backend.send (exploration noise — see
|
// output pipeline and BEFORE backend.send (exploration noise — see
|
||||||
|
|
@ -149,11 +148,6 @@ export class Spine implements EngineSink {
|
||||||
this.bump_();
|
this.bump_();
|
||||||
}
|
}
|
||||||
|
|
||||||
setWeights(w: Float32Array): void {
|
|
||||||
this.liveWeights = w;
|
|
||||||
this.bump_();
|
|
||||||
}
|
|
||||||
|
|
||||||
emit(event: string, payload?: unknown): void {
|
emit(event: string, payload?: unknown): void {
|
||||||
const set = this.eventListeners.get(event);
|
const set = this.eventListeners.get(event);
|
||||||
if (set) for (const fn of set) fn(payload);
|
if (set) for (const fn of set) fn(payload);
|
||||||
|
|
@ -333,10 +327,6 @@ export class Spine implements EngineSink {
|
||||||
return this.routedBuf;
|
return this.routedBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
weights(): Float32Array {
|
|
||||||
return this.liveWeights;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- useSyncExternalStore plumbing ---------------------------------
|
// ---- useSyncExternalStore plumbing ---------------------------------
|
||||||
|
|
||||||
subscribe = (cb: () => void): (() => void) => {
|
subscribe = (cb: () => void): (() => void) => {
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ export interface NispsModule {
|
||||||
// non-positive/null args fall back to the compiled defaults (32→[10,14,18]→126).
|
// non-positive/null args fall back to the compiled defaults (32→[10,14,18]→126).
|
||||||
_nisps_ml_create(input_size: number, output_size: number, hidden_ptr: number, n_hidden: number, seed: number): number;
|
_nisps_ml_create(input_size: number, output_size: number, hidden_ptr: number, n_hidden: number, seed: number): number;
|
||||||
_nisps_ml_destroy(ml: number): void;
|
_nisps_ml_destroy(ml: number): void;
|
||||||
_nisps_ml_reset(ml: number): void;
|
|
||||||
// Reshape = new net at the new dims, warm-started with the overlapping
|
// Reshape = new net at the new dims, warm-started with the overlapping
|
||||||
// weights; feedback state resets. Returns 1 on success (0 = no change).
|
// weights; feedback state resets. Returns 1 on success (0 = no change).
|
||||||
_nisps_ml_reshape(ml: number, input_size: number, output_size: number, hidden_ptr: number, n_hidden: number, spread: number): number;
|
_nisps_ml_reshape(ml: number, input_size: number, output_size: number, hidden_ptr: number, n_hidden: number, spread: number): number;
|
||||||
|
|
@ -50,14 +49,12 @@ export interface NispsModule {
|
||||||
|
|
||||||
// ML examples.
|
// ML examples.
|
||||||
_nisps_ml_clear_examples(ml: number): void;
|
_nisps_ml_clear_examples(ml: number): void;
|
||||||
_nisps_ml_example_count(ml: number): number;
|
|
||||||
|
|
||||||
// ML weights.
|
// ML weights.
|
||||||
_nisps_ml_weight_count(ml: number): number;
|
_nisps_ml_weight_count(ml: number): number;
|
||||||
_nisps_ml_get_weights(ml: number, out_ptr: number): void;
|
_nisps_ml_get_weights(ml: number, out_ptr: number): void;
|
||||||
_nisps_ml_set_weights(ml: number, in_ptr: number): void;
|
_nisps_ml_set_weights(ml: number, in_ptr: number): void;
|
||||||
_nisps_ml_draw_weights(ml: number, spread: number): void;
|
_nisps_ml_draw_weights(ml: number, spread: number): void;
|
||||||
_nisps_ml_move_weights(ml: number, speed: number, spread: number, mask_ptr: number): void;
|
|
||||||
_nisps_ml_get_layer_stats(ml: number, out_ptr: number): void;
|
_nisps_ml_get_layer_stats(ml: number, out_ptr: number): void;
|
||||||
// Null ml reports the DEFAULT shape; a handle reports its runtime shape.
|
// Null ml reports the DEFAULT shape; a handle reports its runtime shape.
|
||||||
_nisps_ml_describe(ml: number, out_ptr: number): void;
|
_nisps_ml_describe(ml: number, out_ptr: number): void;
|
||||||
|
|
@ -68,7 +65,6 @@ export interface NispsModule {
|
||||||
_nisps_ml_feedback_set_mode(ml: number, mode: number): void;
|
_nisps_ml_feedback_set_mode(ml: number, mode: number): void;
|
||||||
_nisps_ml_feedback_get_mode(ml: number): number;
|
_nisps_ml_feedback_get_mode(ml: number): number;
|
||||||
_nisps_ml_feedback_exploring(ml: number): number; // 1 = exploring
|
_nisps_ml_feedback_exploring(ml: number): number; // 1 = exploring
|
||||||
_nisps_ml_feedback_learning_paused(ml: number): number; // 1 = paused
|
|
||||||
_nisps_ml_feedback_set_focus(ml: number, mask_ptr: number, n: number): void;
|
_nisps_ml_feedback_set_focus(ml: number, mask_ptr: number, n: number): void;
|
||||||
_nisps_ml_feedback_down(
|
_nisps_ml_feedback_down(
|
||||||
ml: number,
|
ml: number,
|
||||||
|
|
@ -78,7 +74,6 @@ export interface NispsModule {
|
||||||
pin_mask_ptr: number,
|
pin_mask_ptr: number,
|
||||||
): number;
|
): number;
|
||||||
_nisps_ml_feedback_up(ml: number): number;
|
_nisps_ml_feedback_up(ml: number): number;
|
||||||
_nisps_ml_feedback_drag(ml: number): number;
|
|
||||||
// Returns 1 if `out` holds a static-bypass vector (skip process()); else 0.
|
// Returns 1 if `out` holds a static-bypass vector (skip process()); else 0.
|
||||||
_nisps_ml_feedback_static_output(ml: number, out_ptr: number): number;
|
_nisps_ml_feedback_static_output(ml: number, out_ptr: number): number;
|
||||||
|
|
||||||
|
|
@ -94,8 +89,6 @@ export interface NispsModule {
|
||||||
_nisps_ml_feedback_like(ml: number): void; // Exploring→Placing (freeze output)
|
_nisps_ml_feedback_like(ml: number): void; // Exploring→Placing (freeze output)
|
||||||
_nisps_ml_feedback_commit_place(ml: number): void; // Placing→Idle (restore real net)
|
_nisps_ml_feedback_commit_place(ml: number): void; // Placing→Idle (restore real net)
|
||||||
_nisps_ml_feedback_cancel_place(ml: number): void; // Placing→Exploring
|
_nisps_ml_feedback_cancel_place(ml: number): void; // Placing→Exploring
|
||||||
_nisps_ml_feedback_placing(ml: number): number; // 1 = Placing
|
|
||||||
_nisps_ml_feedback_state(ml: number): number; // 0=Idle 1=Exploring 2=Placing
|
|
||||||
_nisps_ml_feedback_undo_depth(ml: number): number;
|
_nisps_ml_feedback_undo_depth(ml: number): number;
|
||||||
// Writes placed/committed output (outputSize floats) into out; returns 1 if written.
|
// Writes placed/committed output (outputSize floats) into out; returns 1 if written.
|
||||||
_nisps_ml_feedback_placed_output(ml: number, out_ptr: number): number;
|
_nisps_ml_feedback_placed_output(ml: number, out_ptr: number): number;
|
||||||
|
|
@ -123,8 +116,6 @@ export interface NispsModule {
|
||||||
_nisps_ml_jolt_step(ml: number): void;
|
_nisps_ml_jolt_step(ml: number): void;
|
||||||
_nisps_ml_jolt_release(ml: number): void;
|
_nisps_ml_jolt_release(ml: number): void;
|
||||||
_nisps_ml_jolt_active(ml: number): number; // 1 = held/active
|
_nisps_ml_jolt_active(ml: number): number; // 1 = held/active
|
||||||
_nisps_ml_jolt_lr_scale(ml: number): number; // post-release LR ramp multiplier
|
|
||||||
_nisps_ml_jolt_tick_lr_ramp(ml: number): void;
|
|
||||||
_nisps_ml_explore_intensity(ml: number, level: number): void;
|
_nisps_ml_explore_intensity(ml: number, level: number): void;
|
||||||
_nisps_ml_explore_get_intensity(ml: number): number;
|
_nisps_ml_explore_get_intensity(ml: number): number;
|
||||||
_nisps_ml_explore_apply(ml: number, inout_ptr: number, n: number): void;
|
_nisps_ml_explore_apply(ml: number, inout_ptr: number, n: number): void;
|
||||||
|
|
@ -145,9 +136,6 @@ export interface NispsModule {
|
||||||
// In place: processes the first n floats of inout_ptr.
|
// In place: processes the first n floats of inout_ptr.
|
||||||
_nisps_output_process(p: number, inout_ptr: number, n: number, dt_s: number): void;
|
_nisps_output_process(p: number, inout_ptr: number, n: number, dt_s: number): void;
|
||||||
_nisps_output_reset(p: number): void;
|
_nisps_output_reset(p: number): void;
|
||||||
_nisps_pipeline_state_size(p: number): number;
|
|
||||||
_nisps_pipeline_save_state(p: number, out_ptr: number): void;
|
|
||||||
_nisps_pipeline_load_state(p: number, in_ptr: number, n: number): void;
|
|
||||||
|
|
||||||
// Curve catalog (one-core-engine P4). ids 0..6 = nisps::Curve (param ignored);
|
// Curve catalog (one-core-engine P4). ids 0..6 = nisps::Curve (param ignored);
|
||||||
// id 7 = centred power (param = exponent). nisps/core/math.hpp is the single
|
// id 7 = centred power (param = exponent). nisps/core/math.hpp is the single
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
* `mlStore.__setState(produce(...))` / `mlStore.__setOutputs(...)` /
|
* `mlStore.__setState(produce(...))` / `mlStore.__setOutputs(...)` /
|
||||||
* `mlStore.__setWeights(...)` / `coreBus.emit(...)`, this class calls the
|
* `mlStore.__setWeights(...)` / `coreBus.emit(...)`, this class calls the
|
||||||
* injected {@link EngineSink} (`sink.setState({...})` with a PLAIN patch
|
* injected {@link EngineSink} (`sink.setState({...})` with a PLAIN patch
|
||||||
* object — no `produce` mutator, `sink.setOutputs/setWeights/emit`).
|
* object — no `produce` mutator, `sink.setOutputs/emit`).
|
||||||
* - Glue + WASM URLs resolve via `import.meta.env.BASE_URL` (not `/nisps.*`).
|
* - Glue + WASM URLs resolve via `import.meta.env.BASE_URL` (not `/nisps.*`).
|
||||||
* - The `nisps_ml_feedback_*` C ABI (already exported by the WASM build) is
|
* - The `nisps_ml_feedback_*` C ABI (already exported by the WASM build) is
|
||||||
* now bound and surfaced via the `feedback*` methods. The playground never
|
* now bound and surfaced via the `feedback*` methods. The playground never
|
||||||
|
|
@ -233,7 +233,6 @@ export class WasmIML {
|
||||||
ready: true,
|
ready: true,
|
||||||
});
|
});
|
||||||
this.sink.setOutputs(new Float32Array(this.arch_.outputSize));
|
this.sink.setOutputs(new Float32Array(this.arch_.outputSize));
|
||||||
this.publishWeights_();
|
|
||||||
|
|
||||||
this.tryLoadFromStorage_();
|
this.tryLoadFromStorage_();
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +395,6 @@ export class WasmIML {
|
||||||
lossHistory: [],
|
lossHistory: [],
|
||||||
});
|
});
|
||||||
this.sink.setOutputs(new Float32Array(this.arch_.outputSize));
|
this.sink.setOutputs(new Float32Array(this.arch_.outputSize));
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('ml.reshaped', {
|
this.sink.emit('ml.reshaped', {
|
||||||
inputSize: this.arch_.inputSize,
|
inputSize: this.arch_.inputSize,
|
||||||
outputSize: this.arch_.outputSize,
|
outputSize: this.arch_.outputSize,
|
||||||
|
|
@ -616,7 +614,6 @@ export class WasmIML {
|
||||||
// The C++ MLP stores per-iter history but it isn't exposed via the WASM
|
// The C++ MLP stores per-iter history but it isn't exposed via the WASM
|
||||||
// bindings yet, so this is a single-element array.
|
// bindings yet, so this is a single-element array.
|
||||||
this.sink.setState({ lastLoss: loss, lossHistory: [loss] });
|
this.sink.setState({ lastLoss: loss, lossHistory: [loss] });
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('ml.trained', { loss });
|
this.sink.emit('ml.trained', { loss });
|
||||||
this.scheduleSave_();
|
this.scheduleSave_();
|
||||||
return loss;
|
return loss;
|
||||||
|
|
@ -677,18 +674,10 @@ export class WasmIML {
|
||||||
|
|
||||||
randomiseWeights(spread = 0.6): void {
|
randomiseWeights(spread = 0.6): void {
|
||||||
this.module._nisps_ml_draw_weights(this.mlHandle, spread);
|
this.module._nisps_ml_draw_weights(this.mlHandle, spread);
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('ml.delta_update', { reason: 'randomise' });
|
this.sink.emit('ml.delta_update', { reason: 'randomise' });
|
||||||
this.scheduleSave_();
|
this.scheduleSave_();
|
||||||
}
|
}
|
||||||
|
|
||||||
moveWeights(speed: number, spread: number, pinMask?: Uint8Array): void {
|
|
||||||
const maskPtr = this.writePinMask_(pinMask);
|
|
||||||
this.module._nisps_ml_move_weights(this.mlHandle, speed, spread, maskPtr);
|
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('ml.delta_update', { reason: 'thumbs_down' });
|
|
||||||
}
|
|
||||||
|
|
||||||
private writePinMask_(pinMask?: Uint8Array): number {
|
private writePinMask_(pinMask?: Uint8Array): number {
|
||||||
if (!pinMask) return 0;
|
if (!pinMask) return 0;
|
||||||
const sz = Math.min(pinMask.length, this.arch_.outputSize);
|
const sz = Math.min(pinMask.length, this.arch_.outputSize);
|
||||||
|
|
@ -717,10 +706,6 @@ export class WasmIML {
|
||||||
return this.module._nisps_ml_feedback_exploring(this.mlHandle) === 1;
|
return this.module._nisps_ml_feedback_exploring(this.mlHandle) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
feedbackLearningPaused(): boolean {
|
|
||||||
return this.module._nisps_ml_feedback_learning_paused(this.mlHandle) === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Restrict feedback to a subset of outputs (solo / focus). null clears it. */
|
/** Restrict feedback to a subset of outputs (solo / focus). null clears it. */
|
||||||
feedbackSetFocus(mask: Uint8Array | null): void {
|
feedbackSetFocus(mask: Uint8Array | null): void {
|
||||||
if (!mask || mask.length === 0) {
|
if (!mask || mask.length === 0) {
|
||||||
|
|
@ -735,7 +720,6 @@ export class WasmIML {
|
||||||
/** Positive feedback (thumbs-up). Returns the FeedbackAction int. */
|
/** Positive feedback (thumbs-up). Returns the FeedbackAction int. */
|
||||||
feedbackUp(): number {
|
feedbackUp(): number {
|
||||||
const action = this.module._nisps_ml_feedback_up(this.mlHandle);
|
const action = this.module._nisps_ml_feedback_up(this.mlHandle);
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('feedback.up', { action });
|
this.sink.emit('feedback.up', { action });
|
||||||
this.scheduleSave_();
|
this.scheduleSave_();
|
||||||
return action;
|
return action;
|
||||||
|
|
@ -755,19 +739,11 @@ export class WasmIML {
|
||||||
}
|
}
|
||||||
const maskPtr = this.writePinMask_(pinMask);
|
const maskPtr = this.writePinMask_(pinMask);
|
||||||
const action = this.module._nisps_ml_feedback_down(this.mlHandle, outPtr, speed, spread, maskPtr);
|
const action = this.module._nisps_ml_feedback_down(this.mlHandle, outPtr, speed, spread, maskPtr);
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('feedback.down', { action });
|
this.sink.emit('feedback.down', { action });
|
||||||
this.scheduleSave_();
|
this.scheduleSave_();
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Drag (continuous perturbation) tick. Returns the FeedbackAction int. */
|
|
||||||
feedbackDrag(): number {
|
|
||||||
const action = this.module._nisps_ml_feedback_drag(this.mlHandle);
|
|
||||||
this.publishWeights_();
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a static bypass vector is active, copies it into `out` and returns true
|
* If a static bypass vector is active, copies it into `out` and returns true
|
||||||
* (the caller should NOT call process()); otherwise returns false.
|
* (the caller should NOT call process()); otherwise returns false.
|
||||||
|
|
@ -784,38 +760,32 @@ export class WasmIML {
|
||||||
|
|
||||||
// ---- ExploreAndPlace lifecycle (shared C++ core; mode 'explore_and_place') --
|
// ---- ExploreAndPlace lifecycle (shared C++ core; mode 'explore_and_place') --
|
||||||
// The C++ core owns the weight snapshot / scratchpad / undo ring; THIS class
|
// The C++ core owns the weight snapshot / scratchpad / undo ring; THIS class
|
||||||
// only forwards calls + republishes weights. Example-storage + training stay
|
// only forwards calls. Example-storage + training stay with the caller
|
||||||
// with the caller (FeedbackController.ts), preserving the "caller owns
|
// (FeedbackController.ts), preserving the "caller owns training" contract.
|
||||||
// training" contract.
|
|
||||||
|
|
||||||
/** Idle→Exploring: snapshot the real net, randomise a scratchpad. */
|
/** Idle→Exploring: snapshot the real net, randomise a scratchpad. */
|
||||||
feedbackEnterExplore(spread: number): void {
|
feedbackEnterExplore(spread: number): void {
|
||||||
this.module._nisps_ml_feedback_enter_explore(this.mlHandle, spread);
|
this.module._nisps_ml_feedback_enter_explore(this.mlHandle, spread);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exploring→Idle: restore the real net, discard the scratchpad. */
|
/** Exploring→Idle: restore the real net, discard the scratchpad. */
|
||||||
feedbackExitExplore(): void {
|
feedbackExitExplore(): void {
|
||||||
this.module._nisps_ml_feedback_exit_explore(this.mlHandle);
|
this.module._nisps_ml_feedback_exit_explore(this.mlHandle);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exploring scratchpad op: re-randomise (undoable). */
|
/** Exploring scratchpad op: re-randomise (undoable). */
|
||||||
feedbackReroll(spread: number): void {
|
feedbackReroll(spread: number): void {
|
||||||
this.module._nisps_ml_feedback_reroll(this.mlHandle, spread);
|
this.module._nisps_ml_feedback_reroll(this.mlHandle, spread);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exploring scratchpad op: small bounded perturbation (undoable). */
|
/** Exploring scratchpad op: small bounded perturbation (undoable). */
|
||||||
feedbackNudge(amount: number): void {
|
feedbackNudge(amount: number): void {
|
||||||
this.module._nisps_ml_feedback_nudge(this.mlHandle, amount);
|
this.module._nisps_ml_feedback_nudge(this.mlHandle, amount);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exploring scratchpad op: undo the last reroll/nudge. */
|
/** Exploring scratchpad op: undo the last reroll/nudge. */
|
||||||
feedbackUndo(): void {
|
feedbackUndo(): void {
|
||||||
this.module._nisps_ml_feedback_undo(this.mlHandle);
|
this.module._nisps_ml_feedback_undo(this.mlHandle);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Exploring→Placing: freeze the scratchpad output at its current input. */
|
/** Exploring→Placing: freeze the scratchpad output at its current input. */
|
||||||
|
|
@ -826,7 +796,6 @@ export class WasmIML {
|
||||||
/** Placing→Idle: restore the real net. Caller then stores +1 + trains. */
|
/** Placing→Idle: restore the real net. Caller then stores +1 + trains. */
|
||||||
feedbackCommitPlace(): void {
|
feedbackCommitPlace(): void {
|
||||||
this.module._nisps_ml_feedback_commit_place(this.mlHandle);
|
this.module._nisps_ml_feedback_commit_place(this.mlHandle);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Placing→Exploring: back out without storing. */
|
/** Placing→Exploring: back out without storing. */
|
||||||
|
|
@ -834,15 +803,6 @@ export class WasmIML {
|
||||||
this.module._nisps_ml_feedback_cancel_place(this.mlHandle);
|
this.module._nisps_ml_feedback_cancel_place(this.mlHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
feedbackPlacing(): boolean {
|
|
||||||
return this.module._nisps_ml_feedback_placing(this.mlHandle) === 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** ExploreState: 0=Idle 1=Exploring 2=Placing. */
|
|
||||||
feedbackState(): number {
|
|
||||||
return this.module._nisps_ml_feedback_state(this.mlHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
feedbackUndoDepth(): number {
|
feedbackUndoDepth(): number {
|
||||||
return this.module._nisps_ml_feedback_undo_depth(this.mlHandle);
|
return this.module._nisps_ml_feedback_undo_depth(this.mlHandle);
|
||||||
}
|
}
|
||||||
|
|
@ -867,7 +827,7 @@ export class WasmIML {
|
||||||
* Geometric dislike: push the current mapping away from the liked centroid.
|
* Geometric dislike: push the current mapping away from the liked centroid.
|
||||||
* `heardVec` is the kDefaultOutputs vector the user is HEARING (post-pipeline —
|
* `heardVec` is the kDefaultOutputs vector the user is HEARING (post-pipeline —
|
||||||
* with a null/raw vector the cold-start has a zero MSE derivative and is inert).
|
* with a null/raw vector the cold-start has a zero MSE derivative and is inert).
|
||||||
* `lr <= 0` uses the C++ controller default. Mutates weights → republishes.
|
* `lr <= 0` uses the C++ controller default. Mutates weights in place.
|
||||||
* Returns the FeedbackAction int (14=GeometricPush, 15=GeometricColdStart).
|
* Returns the FeedbackAction int (14=GeometricPush, 15=GeometricColdStart).
|
||||||
*/
|
*/
|
||||||
feedbackDislikeGeometric(heardVec?: Float32Array, lr = 0): number {
|
feedbackDislikeGeometric(heardVec?: Float32Array, lr = 0): number {
|
||||||
|
|
@ -879,7 +839,6 @@ export class WasmIML {
|
||||||
outPtr = this.feedbackBuf.ptr;
|
outPtr = this.feedbackBuf.ptr;
|
||||||
}
|
}
|
||||||
const action = this.module._nisps_ml_feedback_dislike_geometric(this.mlHandle, outPtr, lr);
|
const action = this.module._nisps_ml_feedback_dislike_geometric(this.mlHandle, outPtr, lr);
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('feedback.down', { action });
|
this.sink.emit('feedback.down', { action });
|
||||||
this.scheduleSave_();
|
this.scheduleSave_();
|
||||||
return action;
|
return action;
|
||||||
|
|
@ -925,10 +884,9 @@ export class WasmIML {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** One ~200 Hz morph tick while held (no-op when inactive). C-side get→glide→
|
/** One ~200 Hz morph tick while held (no-op when inactive). C-side get→glide→
|
||||||
* set of the flat weights; republish so weight-health views + persistence follow. */
|
* set of the flat weights; scheduleSave_ persists the result. */
|
||||||
joltStep(): void {
|
joltStep(): void {
|
||||||
this.module._nisps_ml_jolt_step(this.mlHandle);
|
this.module._nisps_ml_jolt_step(this.mlHandle);
|
||||||
this.publishWeights_();
|
|
||||||
this.scheduleSave_();
|
this.scheduleSave_();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -941,15 +899,6 @@ export class WasmIML {
|
||||||
return this.module._nisps_ml_jolt_active(this.mlHandle) === 1;
|
return this.module._nisps_ml_jolt_active(this.mlHandle) === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Post-release LR-ramp multiplier (0 while held → 1 over ~5 s of ticks). */
|
|
||||||
joltLrScale(): number {
|
|
||||||
return this.module._nisps_ml_jolt_lr_scale(this.mlHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
joltTickLrRamp(): void {
|
|
||||||
this.module._nisps_ml_jolt_tick_lr_ramp(this.mlHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Exploration amount in [0,1]; 0 disables (inert — parity-safe). */
|
/** Exploration amount in [0,1]; 0 disables (inert — parity-safe). */
|
||||||
setExploreIntensity(level: number): void {
|
setExploreIntensity(level: number): void {
|
||||||
this.module._nisps_ml_explore_intensity(this.mlHandle, level);
|
this.module._nisps_ml_explore_intensity(this.mlHandle, level);
|
||||||
|
|
@ -987,7 +936,6 @@ export class WasmIML {
|
||||||
}
|
}
|
||||||
this.weightsBuf.view.set(w as Float32Array, 0);
|
this.weightsBuf.view.set(w as Float32Array, 0);
|
||||||
this.module._nisps_ml_set_weights(this.mlHandle, this.weightsBuf.ptr);
|
this.module._nisps_ml_set_weights(this.mlHandle, this.weightsBuf.ptr);
|
||||||
this.publishWeights_();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLayerStats(): LayerStats[] {
|
getLayerStats(): LayerStats[] {
|
||||||
|
|
@ -1010,20 +958,6 @@ export class WasmIML {
|
||||||
return new Float32Array(this.statsBuf.view);
|
return new Float32Array(this.statsBuf.view);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
// Misc
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
reset(): void {
|
|
||||||
this.module._nisps_ml_reset(this.mlHandle);
|
|
||||||
this.dataset.clear();
|
|
||||||
this.lastLoss_ = null;
|
|
||||||
this.sink.setState({ exampleCount: 0, lastLoss: null, lossHistory: [] });
|
|
||||||
this.publishWeights_();
|
|
||||||
this.sink.emit('ml.examples_cleared', undefined);
|
|
||||||
this.scheduleSave_();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
// Persistence
|
// Persistence
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
@ -1089,9 +1023,4 @@ export class WasmIML {
|
||||||
console.warn('[wasm-iml] tryLoadFromStorage failed:', err);
|
console.warn('[wasm-iml] tryLoadFromStorage failed:', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private publishWeights_(): void {
|
|
||||||
const w = this.getWeights();
|
|
||||||
this.sink.setWeights(w);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -102,13 +102,6 @@ class NispsProcessor extends AudioWorkletProcessor {
|
||||||
*/
|
*/
|
||||||
private async init_(bytes: ArrayBuffer, sampleRate: number): Promise<void> {
|
private async init_(bytes: ArrayBuffer, sampleRate: number): Promise<void> {
|
||||||
const memory = new WebAssembly.Memory({ initial: 128, maximum: 4096, shared: false });
|
const memory = new WebAssembly.Memory({ initial: 128, maximum: 4096, shared: false });
|
||||||
const imports: WebAssembly.Imports = {
|
|
||||||
// Emscripten import "a" group; field names match the generated JS.
|
|
||||||
a: {
|
|
||||||
a: () => { throw new Error('wasm aborted'); },
|
|
||||||
b: () => false, // _emscripten_resize_heap returning 0 disables growth
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const compiled = await WebAssembly.compile(bytes);
|
const compiled = await WebAssembly.compile(bytes);
|
||||||
// Discover the actual import shape from the module — names like "a",
|
// Discover the actual import shape from the module — names like "a",
|
||||||
|
|
@ -119,13 +112,20 @@ class NispsProcessor extends AudioWorkletProcessor {
|
||||||
if (!reshaped[desc.module]) reshaped[desc.module] = {} as WebAssembly.ModuleImports;
|
if (!reshaped[desc.module]) reshaped[desc.module] = {} as WebAssembly.ModuleImports;
|
||||||
const mod = reshaped[desc.module] as WebAssembly.ModuleImports;
|
const mod = reshaped[desc.module] as WebAssembly.ModuleImports;
|
||||||
if (desc.kind === 'function') {
|
if (desc.kind === 'function') {
|
||||||
if (desc.name === 'c') {
|
if (desc.name === 'a') {
|
||||||
// unused
|
// __abort_js
|
||||||
|
mod[desc.name] = () => { throw new Error('wasm aborted'); };
|
||||||
|
} else if (desc.name === 'b') {
|
||||||
|
// _emscripten_resize_heap: refuse growth in the worklet.
|
||||||
|
mod[desc.name] = (_size: number) => 0;
|
||||||
|
} else {
|
||||||
|
// Unknown import — fail loudly instead of silently returning 0, so a
|
||||||
|
// missing/renamed Emscripten import surfaces immediately instead of
|
||||||
|
// manifesting as silent audio corruption.
|
||||||
|
mod[desc.name] = (..._args: unknown[]) => {
|
||||||
|
throw new Error(`worklet: missing wasm import "${desc.module}.${desc.name}"`);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
mod[desc.name] = (() => {
|
|
||||||
// Generic stub: log + return 0.
|
|
||||||
return (..._args: unknown[]) => 0;
|
|
||||||
})();
|
|
||||||
} else if (desc.kind === 'memory') {
|
} else if (desc.kind === 'memory') {
|
||||||
mod[desc.name] = memory;
|
mod[desc.name] = memory;
|
||||||
} else if (desc.kind === 'table') {
|
} else if (desc.kind === 'table') {
|
||||||
|
|
@ -134,34 +134,12 @@ class NispsProcessor extends AudioWorkletProcessor {
|
||||||
mod[desc.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, 0);
|
mod[desc.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// For known-needed Emscripten imports, supply real implementations.
|
|
||||||
for (const desc of importDesc) {
|
|
||||||
const mod = reshaped[desc.module] as WebAssembly.ModuleImports;
|
|
||||||
// __abort_js
|
|
||||||
if (desc.name === 'a' && desc.kind === 'function') {
|
|
||||||
mod[desc.name] = () => { throw new Error('wasm aborted'); };
|
|
||||||
}
|
|
||||||
// _emscripten_resize_heap
|
|
||||||
if (desc.name === 'b' && desc.kind === 'function') {
|
|
||||||
mod[desc.name] = (_size: number) => 0; // refuse growth in worklet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void imports; // silence unused
|
|
||||||
const wasmInst = await WebAssembly.instantiate(compiled, reshaped);
|
const wasmInst = await WebAssembly.instantiate(compiled, reshaped);
|
||||||
|
|
||||||
// Many Emscripten exports use single-letter mangled names. Discover
|
// Many Emscripten exports use single-letter mangled names. Discover
|
||||||
// by reading the export descriptors.
|
// by reading the export descriptors.
|
||||||
const exDesc = WebAssembly.Module.exports(compiled);
|
const exDesc = WebAssembly.Module.exports(compiled);
|
||||||
const exMap = new Map<string, string>(); // logical name → mangled
|
|
||||||
for (const e of exDesc) {
|
|
||||||
// The exports list includes both the original (with leading
|
|
||||||
// underscore for C funcs) and the mangled single-letter alias used
|
|
||||||
// in the import section. We only see the export side here, but
|
|
||||||
// Emscripten in modern versions also re-exports the C names with
|
|
||||||
// their leading-underscore form. Walk both.
|
|
||||||
exMap.set(e.name, e.name);
|
|
||||||
}
|
|
||||||
const exports = wasmInst.exports as Record<string, WebAssembly.ExportValue>;
|
const exports = wasmInst.exports as Record<string, WebAssembly.ExportValue>;
|
||||||
|
|
||||||
function pickFn(...names: string[]): (...args: number[]) => number {
|
function pickFn(...names: string[]): (...args: number[]) => number {
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,10 @@ See `bindings.cpp` for the full list. Summary:
|
||||||
|
|
||||||
| Group | Functions |
|
| Group | Functions |
|
||||||
|-----------|------------------------------------------------------------------------------|
|
|-----------|------------------------------------------------------------------------------|
|
||||||
| ML life | `nisps_ml_create`, `nisps_ml_destroy`, `nisps_ml_reset`, `nisps_ml_reshape` |
|
| ML life | `nisps_ml_create`, `nisps_ml_destroy`, `nisps_ml_reshape` |
|
||||||
| ML I/O | `nisps_ml_set_input`, `nisps_ml_process`, `nisps_ml_outputs`, `nisps_ml_infer_batch` |
|
| ML I/O | `nisps_ml_set_input`, `nisps_ml_process`, `nisps_ml_outputs`, `nisps_ml_infer_batch` |
|
||||||
| Training | `nisps_ml_add_example`, `nisps_ml_train`, `nisps_ml_eval_loss`, `nisps_ml_clear_examples`, `nisps_ml_example_count` |
|
| Training | `nisps_ml_add_example`, `nisps_ml_train`, `nisps_ml_eval_loss`, `nisps_ml_clear_examples` |
|
||||||
| Weights | `nisps_ml_weight_count`, `nisps_ml_get_weights`, `nisps_ml_set_weights`, `nisps_ml_draw_weights`, `nisps_ml_move_weights` |
|
| Weights | `nisps_ml_weight_count`, `nisps_ml_get_weights`, `nisps_ml_set_weights`, `nisps_ml_draw_weights` |
|
||||||
| Diag | `nisps_ml_get_layer_stats`, `nisps_ml_describe` |
|
| Diag | `nisps_ml_get_layer_stats`, `nisps_ml_describe` |
|
||||||
| Engines | `nisps_engine_create`, `nisps_engine_destroy`, `nisps_engine_set_params`, `nisps_engine_process_block` |
|
| Engines | `nisps_engine_create`, `nisps_engine_destroy`, `nisps_engine_set_params`, `nisps_engine_process_block` |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -548,18 +548,6 @@ void nisps_ml_draw_weights(void* ml, float spread) {
|
||||||
h->mlp.draw_weights(spread);
|
h->mlp.draw_weights(spread);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
void nisps_ml_move_weights(void* ml, float speed, float spread,
|
|
||||||
const uint8_t* output_pin_mask) {
|
|
||||||
if (!ml) return;
|
|
||||||
auto* h = static_cast<MLHandle*>(ml);
|
|
||||||
std::span<const std::uint8_t> mask;
|
|
||||||
if (output_pin_mask) {
|
|
||||||
mask = std::span<const std::uint8_t>(output_pin_mask, h->n_out());
|
|
||||||
}
|
|
||||||
h->mlp.move_weights(speed, spread, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// ML feedback — the "Down Action" state machine (Avoid / RandomiseOutputs /
|
// ML feedback — the "Down Action" state machine (Avoid / RandomiseOutputs /
|
||||||
// RandomiseMlp). The controller decides WHAT transition happened (returns a
|
// RandomiseMlp). The controller decides WHAT transition happened (returns a
|
||||||
|
|
@ -601,12 +589,6 @@ int nisps_ml_feedback_exploring(void* ml) {
|
||||||
return static_cast<MLHandle*>(ml)->feedback.exploring() ? 1 : 0;
|
return static_cast<MLHandle*>(ml)->feedback.exploring() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
int nisps_ml_feedback_learning_paused(void* ml) {
|
|
||||||
if (!ml) return 0;
|
|
||||||
return static_cast<MLHandle*>(ml)->feedback.learning_paused() ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
EMSCRIPTEN_KEEPALIVE
|
||||||
void nisps_ml_feedback_set_focus(void* ml, const uint8_t* mask, int n) {
|
void nisps_ml_feedback_set_focus(void* ml, const uint8_t* mask, int n) {
|
||||||
if (!ml) return;
|
if (!ml) return;
|
||||||
|
|
@ -640,13 +622,6 @@ int nisps_ml_feedback_up(void* ml) {
|
||||||
return static_cast<int>(h->feedback.on_up(h->mlp));
|
return static_cast<int>(h->feedback.on_up(h->mlp));
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
int nisps_ml_feedback_drag(void* ml) {
|
|
||||||
if (!ml) return 0;
|
|
||||||
auto* h = static_cast<MLHandle*>(ml);
|
|
||||||
return static_cast<int>(h->feedback.on_drag(h->mlp));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If returns 1, `out` (n_out floats) holds the static bypass vector
|
// If returns 1, `out` (n_out floats) holds the static bypass vector
|
||||||
// and the caller should NOT call nisps_ml_process(); if 0, run process().
|
// and the caller should NOT call nisps_ml_process(); if 0, run process().
|
||||||
EMSCRIPTEN_KEEPALIVE
|
EMSCRIPTEN_KEEPALIVE
|
||||||
|
|
@ -738,20 +713,6 @@ void nisps_ml_feedback_cancel_place(void* ml) {
|
||||||
h->feedback.cancel_place();
|
h->feedback.cancel_place();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 if currently Placing (audition is the frozen vector), else 0.
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
int nisps_ml_feedback_placing(void* ml) {
|
|
||||||
if (!ml) return 0;
|
|
||||||
return static_cast<MLHandle*>(ml)->feedback.placing() ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExploreState int: 0=Idle 1=Exploring 2=Placing.
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
int nisps_ml_feedback_state(void* ml) {
|
|
||||||
if (!ml) return 0;
|
|
||||||
return static_cast<int>(static_cast<MLHandle*>(ml)->feedback.explore_state());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scratchpad undo-ring depth currently available to pop.
|
// Scratchpad undo-ring depth currently available to pop.
|
||||||
EMSCRIPTEN_KEEPALIVE
|
EMSCRIPTEN_KEEPALIVE
|
||||||
int nisps_ml_feedback_undo_depth(void* ml) {
|
int nisps_ml_feedback_undo_depth(void* ml) {
|
||||||
|
|
@ -863,20 +824,6 @@ int nisps_ml_jolt_active(void* ml) {
|
||||||
return static_cast<MLHandle*>(ml)->jolt.active() ? 1 : 0;
|
return static_cast<MLHandle*>(ml)->jolt.active() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post-release learning-rate ramp: multiply the training LR by this (0 while
|
|
||||||
// held, ramps back to 1 over ~5 s of ticks).
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
float nisps_ml_jolt_lr_scale(void* ml) {
|
|
||||||
if (!ml) return 1.f;
|
|
||||||
return static_cast<MLHandle*>(ml)->jolt.lr_scale();
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
void nisps_ml_jolt_tick_lr_ramp(void* ml) {
|
|
||||||
if (!ml) return;
|
|
||||||
static_cast<MLHandle*>(ml)->jolt.tick_lr_ramp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exploration amount in [0,1]; 0 disables (inert — parity-safe).
|
// Exploration amount in [0,1]; 0 disables (inert — parity-safe).
|
||||||
EMSCRIPTEN_KEEPALIVE
|
EMSCRIPTEN_KEEPALIVE
|
||||||
void nisps_ml_explore_intensity(void* ml, float level) {
|
void nisps_ml_explore_intensity(void* ml, float level) {
|
||||||
|
|
@ -914,15 +861,6 @@ void nisps_ml_get_layer_stats(void* ml, float* out_stats) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra helper: lets JS query the example count without having to
|
|
||||||
// shadow-track it. Useful when restoring from snapshot.
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
int nisps_ml_example_count(void* ml) {
|
|
||||||
if (!ml) return 0;
|
|
||||||
auto* h = static_cast<MLHandle*>(ml);
|
|
||||||
return static_cast<int>(h->mlp.example_count());
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
EMSCRIPTEN_KEEPALIVE
|
||||||
void nisps_ml_clear_examples(void* ml) {
|
void nisps_ml_clear_examples(void* ml) {
|
||||||
if (!ml) return;
|
if (!ml) return;
|
||||||
|
|
@ -930,13 +868,6 @@ void nisps_ml_clear_examples(void* ml) {
|
||||||
h->mlp.clear_examples();
|
h->mlp.clear_examples();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
void nisps_ml_reset(void* ml) {
|
|
||||||
if (!ml) return;
|
|
||||||
auto* h = static_cast<MLHandle*>(ml);
|
|
||||||
h->mlp.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Architecture introspection — writes [in, h1, h2, h3, out, n_layers] into a
|
// Architecture introspection — writes [in, h1, h2, h3, out, n_layers] into a
|
||||||
// caller-supplied int buffer. Always 6 ints. With a null handle it reports
|
// caller-supplied int buffer. Always 6 ints. With a null handle it reports
|
||||||
// the DEFAULT shape (what create() yields for non-positive args); with a
|
// the DEFAULT shape (what create() yields for non-positive args); with a
|
||||||
|
|
@ -1070,34 +1001,6 @@ void nisps_output_reset(void* p) {
|
||||||
static_cast<PipelineHandle*>(p)->output.reset();
|
static_cast<PipelineHandle*>(p)->output.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Persistence: [input state (3)] + [output state (1 + 2*count)].
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
int nisps_pipeline_state_size(void* p) {
|
|
||||||
if (!p) return 0;
|
|
||||||
auto* h = static_cast<PipelineHandle*>(p);
|
|
||||||
return static_cast<int>(h->input.state_size() + h->output.state_size());
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
void nisps_pipeline_save_state(void* p, float* out) {
|
|
||||||
if (!p || !out) return;
|
|
||||||
auto* h = static_cast<PipelineHandle*>(p);
|
|
||||||
const std::size_t in_n = h->input.state_size();
|
|
||||||
h->input.save_state(std::span<float>(out, in_n));
|
|
||||||
h->output.save_state(std::span<float>(out + in_n, h->output.state_size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE
|
|
||||||
void nisps_pipeline_load_state(void* p, const float* in, int n) {
|
|
||||||
if (!p || !in || n <= 0) return;
|
|
||||||
auto* h = static_cast<PipelineHandle*>(p);
|
|
||||||
const std::size_t in_n = h->input.state_size();
|
|
||||||
const std::size_t total = static_cast<std::size_t>(n);
|
|
||||||
if (total < in_n) return;
|
|
||||||
h->input.load_state(std::span<const float>(in, in_n));
|
|
||||||
h->output.load_state(std::span<const float>(in + in_n, total - in_n));
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Curve catalog (one-core-engine P4): nisps/core/math.hpp is the single
|
// Curve catalog (one-core-engine P4): nisps/core/math.hpp is the single
|
||||||
// source of truth; the browser samples it instead of mirroring the maths.
|
// source of truth; the browser samples it instead of mirroring the maths.
|
||||||
|
|
|
||||||
|
|
@ -39,32 +39,31 @@ mkdir -p "$OUT"
|
||||||
# function is missing.
|
# function is missing.
|
||||||
EXPORTED_FUNCS='[
|
EXPORTED_FUNCS='[
|
||||||
"_malloc","_free",
|
"_malloc","_free",
|
||||||
"_nisps_ml_create","_nisps_ml_destroy","_nisps_ml_reset","_nisps_ml_reshape",
|
"_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_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_eval_loss",
|
||||||
"_nisps_ml_clear_examples","_nisps_ml_example_count",
|
"_nisps_ml_clear_examples",
|
||||||
"_nisps_ml_weight_count","_nisps_ml_get_weights","_nisps_ml_set_weights",
|
"_nisps_ml_weight_count","_nisps_ml_get_weights","_nisps_ml_set_weights",
|
||||||
"_nisps_ml_draw_weights","_nisps_ml_move_weights",
|
"_nisps_ml_draw_weights",
|
||||||
"_nisps_ml_feedback_set_mode","_nisps_ml_feedback_get_mode",
|
"_nisps_ml_feedback_set_mode","_nisps_ml_feedback_get_mode",
|
||||||
"_nisps_ml_feedback_exploring","_nisps_ml_feedback_learning_paused",
|
"_nisps_ml_feedback_exploring",
|
||||||
"_nisps_ml_feedback_set_focus","_nisps_ml_feedback_down",
|
"_nisps_ml_feedback_set_focus","_nisps_ml_feedback_down",
|
||||||
"_nisps_ml_feedback_up","_nisps_ml_feedback_drag","_nisps_ml_feedback_static_output",
|
"_nisps_ml_feedback_up","_nisps_ml_feedback_static_output",
|
||||||
"_nisps_ml_feedback_enter_explore","_nisps_ml_feedback_exit_explore",
|
"_nisps_ml_feedback_enter_explore","_nisps_ml_feedback_exit_explore",
|
||||||
"_nisps_ml_feedback_reroll","_nisps_ml_feedback_nudge","_nisps_ml_feedback_undo",
|
"_nisps_ml_feedback_reroll","_nisps_ml_feedback_nudge","_nisps_ml_feedback_undo",
|
||||||
"_nisps_ml_feedback_like","_nisps_ml_feedback_commit_place","_nisps_ml_feedback_cancel_place",
|
"_nisps_ml_feedback_like","_nisps_ml_feedback_commit_place","_nisps_ml_feedback_cancel_place",
|
||||||
"_nisps_ml_feedback_placing","_nisps_ml_feedback_state","_nisps_ml_feedback_undo_depth",
|
"_nisps_ml_feedback_undo_depth",
|
||||||
"_nisps_ml_feedback_placed_output",
|
"_nisps_ml_feedback_placed_output",
|
||||||
"_nisps_ml_feedback_dislike_geometric","_nisps_ml_feedback_store_positive",
|
"_nisps_ml_feedback_dislike_geometric","_nisps_ml_feedback_store_positive",
|
||||||
"_nisps_ml_feedback_positive_count","_nisps_ml_feedback_negative_count",
|
"_nisps_ml_feedback_positive_count","_nisps_ml_feedback_negative_count",
|
||||||
"_nisps_ml_feedback_set_avoid_style",
|
"_nisps_ml_feedback_set_avoid_style",
|
||||||
"_nisps_ml_jolt_press","_nisps_ml_jolt_step","_nisps_ml_jolt_release",
|
"_nisps_ml_jolt_press","_nisps_ml_jolt_step","_nisps_ml_jolt_release",
|
||||||
"_nisps_ml_jolt_active","_nisps_ml_jolt_lr_scale","_nisps_ml_jolt_tick_lr_ramp",
|
"_nisps_ml_jolt_active",
|
||||||
"_nisps_ml_explore_intensity","_nisps_ml_explore_get_intensity","_nisps_ml_explore_apply",
|
"_nisps_ml_explore_intensity","_nisps_ml_explore_get_intensity","_nisps_ml_explore_apply",
|
||||||
"_nisps_pipeline_create","_nisps_pipeline_destroy",
|
"_nisps_pipeline_create","_nisps_pipeline_destroy",
|
||||||
"_nisps_input_set_config","_nisps_input_process","_nisps_input_reset",
|
"_nisps_input_set_config","_nisps_input_process","_nisps_input_reset",
|
||||||
"_nisps_output_set_config","_nisps_output_set_freeze_mask",
|
"_nisps_output_set_config","_nisps_output_set_freeze_mask",
|
||||||
"_nisps_output_process","_nisps_output_reset",
|
"_nisps_output_process","_nisps_output_reset",
|
||||||
"_nisps_pipeline_state_size","_nisps_pipeline_save_state","_nisps_pipeline_load_state",
|
|
||||||
"_nisps_curve_apply","_nisps_curve_apply_batch",
|
"_nisps_curve_apply","_nisps_curve_apply_batch",
|
||||||
"_nisps_ml_get_layer_stats","_nisps_ml_describe",
|
"_nisps_ml_get_layer_stats","_nisps_ml_describe",
|
||||||
"_nisps_engine_create","_nisps_engine_destroy",
|
"_nisps_engine_create","_nisps_engine_destroy",
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,6 @@ function bind(Module) {
|
||||||
weightCount: cwrap('nisps_ml_weight_count', 'number', ['number']),
|
weightCount: cwrap('nisps_ml_weight_count', 'number', ['number']),
|
||||||
getWeights: cwrap('nisps_ml_get_weights', null, ['number','number']),
|
getWeights: cwrap('nisps_ml_get_weights', null, ['number','number']),
|
||||||
drawWeights: cwrap('nisps_ml_draw_weights', null, ['number','number']),
|
drawWeights: cwrap('nisps_ml_draw_weights', null, ['number','number']),
|
||||||
moveWeights: cwrap('nisps_ml_move_weights', null, ['number','number','number','number']),
|
|
||||||
feedbackSetMode: cwrap('nisps_ml_feedback_set_mode', null, ['number','number']),
|
feedbackSetMode: cwrap('nisps_ml_feedback_set_mode', null, ['number','number']),
|
||||||
feedbackDown: cwrap('nisps_ml_feedback_down', 'number', ['number','number','number','number','number']),
|
feedbackDown: cwrap('nisps_ml_feedback_down', 'number', ['number','number','number','number','number']),
|
||||||
feedbackUp: cwrap('nisps_ml_feedback_up', 'number', ['number']),
|
feedbackUp: cwrap('nisps_ml_feedback_up', 'number', ['number']),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue