95 lines
3.4 KiB
JavaScript
95 lines
3.4 KiB
JavaScript
|
|
// ShapeSeq param mapping layer
|
||
|
|
// Maps fixed-size MLP outputs (16 values [0,1]) to variable-count primitive params
|
||
|
|
//
|
||
|
|
// The sequence MLP always outputs a fixed number of values (default 16).
|
||
|
|
// The primitive chain has a variable number of params depending on which
|
||
|
|
// primitives are active. This module bridges the two via automatic distribution:
|
||
|
|
// - N <= mlpOutputCount: each param gets one dedicated output
|
||
|
|
// - N > mlpOutputCount: outputs distributed via linear interpolation
|
||
|
|
//
|
||
|
|
// Port-ready: Float32Array, no closures, pure functions.
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create a param mapper instance for a given MLP output count.
|
||
|
|
* @param {number} mlpOutputCount - number of MLP outputs (e.g. 16)
|
||
|
|
* @returns {{ map: Function, mapWithSchema: Function, mlpOutputCount: number }}
|
||
|
|
*/
|
||
|
|
export function createParamMap(mlpOutputCount) {
|
||
|
|
if (!Number.isInteger(mlpOutputCount) || mlpOutputCount < 1) {
|
||
|
|
throw new Error('mlpOutputCount must be a positive integer');
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
mlpOutputCount,
|
||
|
|
map,
|
||
|
|
mapWithSchema,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Map MLP outputs to N primitive params via automatic distribution.
|
||
|
|
*
|
||
|
|
* If paramCount <= mlpOutputCount, each param gets one dedicated output
|
||
|
|
* (first paramCount outputs used, rest ignored).
|
||
|
|
*
|
||
|
|
* If paramCount > mlpOutputCount, outputs are distributed via linear
|
||
|
|
* interpolation so that the first param maps to the first output and the
|
||
|
|
* last param maps to the last output, with intermediate params interpolated.
|
||
|
|
*
|
||
|
|
* @param {Float32Array|number[]} mlpOutputs - MLP output values [0,1]
|
||
|
|
* @param {number} paramCount - number of primitive params to produce
|
||
|
|
* @returns {Float32Array} mapped values [0,1], length = paramCount
|
||
|
|
*/
|
||
|
|
export function map(mlpOutputs, paramCount) {
|
||
|
|
const mlpCount = mlpOutputs.length;
|
||
|
|
const result = new Float32Array(paramCount);
|
||
|
|
|
||
|
|
if (paramCount === 0) return result;
|
||
|
|
|
||
|
|
if (paramCount <= mlpCount) {
|
||
|
|
// Direct mapping: each param gets one dedicated output
|
||
|
|
for (let i = 0; i < paramCount; i++) {
|
||
|
|
result[i] = mlpOutputs[i];
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// Interpolated mapping: spread mlpCount outputs across paramCount params
|
||
|
|
// param[i] maps to a fractional position in the output array
|
||
|
|
// param[0] -> output[0], param[paramCount-1] -> output[mlpCount-1]
|
||
|
|
const scale = paramCount > 1 ? (mlpCount - 1) / (paramCount - 1) : 0;
|
||
|
|
|
||
|
|
for (let i = 0; i < paramCount; i++) {
|
||
|
|
const pos = i * scale;
|
||
|
|
const lo = pos | 0; // floor
|
||
|
|
const hi = lo + 1 < mlpCount ? lo + 1 : lo;
|
||
|
|
const frac = pos - lo;
|
||
|
|
result[i] = mlpOutputs[lo] + (mlpOutputs[hi] - mlpOutputs[lo]) * frac;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Map MLP outputs to primitive params and apply per-param min/max scaling.
|
||
|
|
*
|
||
|
|
* Each param schema defines { min, max } (both [0,1]). The mapped [0,1]
|
||
|
|
* value is scaled into [min, max] for each param.
|
||
|
|
*
|
||
|
|
* @param {Float32Array|number[]} mlpOutputs - MLP output values [0,1]
|
||
|
|
* @param {Array<{ min: number, max: number }>} paramSchemas - per-param range definitions
|
||
|
|
* @returns {Float32Array} scaled values, length = paramSchemas.length
|
||
|
|
*/
|
||
|
|
export function mapWithSchema(mlpOutputs, paramSchemas) {
|
||
|
|
const paramCount = paramSchemas.length;
|
||
|
|
const mapped = map(mlpOutputs, paramCount);
|
||
|
|
|
||
|
|
for (let i = 0; i < paramCount; i++) {
|
||
|
|
const schema = paramSchemas[i];
|
||
|
|
const min = schema.min !== undefined ? schema.min : 0;
|
||
|
|
const max = schema.max !== undefined ? schema.max : 1;
|
||
|
|
mapped[i] = min + mapped[i] * (max - min);
|
||
|
|
}
|
||
|
|
|
||
|
|
return mapped;
|
||
|
|
}
|