export type MLPActivation = 'identity' | 'logistic' | 'tanh' | 'relu'; export type MLPSolver = 'adam' | 'sgd'; export type MLPLearningRateSchedule = 'constant' | 'invscaling' | 'adaptive'; export type MLPOutActivation = 'identity' | 'logistic' | 'softmax'; export type MLPLossKind = 'log' | 'binaryLog' | 'squared'; export interface MLPProps { hiddenLayerSizes?: number[]; activation?: MLPActivation; solver?: MLPSolver; alpha?: number; batchSize?: number | 'auto'; learningRate?: MLPLearningRateSchedule; learningRateInit?: number; powerT?: number; maxIter?: number; shuffle?: boolean; randomState?: number; tol?: number; momentum?: number; nesterovsMomentum?: boolean; earlyStopping?: boolean; validationFraction?: number; beta1?: number; beta2?: number; epsilon?: number; nIterNoChange?: number; } /** Resolved, validated hyper-parameters (exactly the getParams() shape). */ export interface MLPParams { hiddenLayerSizes: number[]; activation: MLPActivation; solver: MLPSolver; alpha: number; batchSize: number | 'auto'; learningRate: MLPLearningRateSchedule; learningRateInit: number; powerT: number; maxIter: number; shuffle: boolean; randomState: number | undefined; tol: number; momentum: number; nesterovsMomentum: boolean; earlyStopping: boolean; validationFraction: number; beta1: number; beta2: number; epsilon: number; nIterNoChange: number; } /** Resolve props to the canonical parameter set with sklearn's defaults. */ export declare function resolveMLPProps(props?: MLPProps): MLPParams; export declare function validateMLPFitInput(X: number[][], y: ArrayLike): void; export interface MLPWeights { /** coefs[l][i][j]: weight from unit i of layer l to unit j of layer l+1. */ coefs: number[][][]; intercepts: number[][]; } /** * sklearn `_init_coef`: uniform in [-bound, bound] with * bound = sqrt(factor / (fanIn + fanOut)), factor 2 for logistic, else 6. * Weights are drawn row-major, then the biases — one RNG stream for the * whole net, so a fixed randomState fully determines the init. */ export declare function initMLPWeights(layerUnits: number[], activation: MLPActivation, rand: () => number): MLPWeights; /** * Forward pass returning the activations of every layer * (activations[0] === X, activations[last] = network output). */ export declare function forwardMLP(X: number[][], weights: MLPWeights, activation: MLPActivation, outActivation: MLPOutActivation): number[][][]; /** Network output only (last layer of `forwardMLP`). */ export declare function predictMLPOutput(X: number[][], weights: MLPWeights, activation: MLPActivation, outActivation: MLPOutActivation): number[][]; export interface MLPTrainConfig { outActivation: MLPOutActivation; lossKind: MLPLossKind; /** * Validation score for early stopping (higher is better): accuracy for * the classifier, R² for the regressor. */ validationScore: (weights: MLPWeights, XVal: number[][], YVal: number[][]) => number; } export interface MLPTrainResult { weights: MLPWeights; lossCurve: number[]; nIter: number; /** Best training loss (null when earlyStopping is on). */ bestLoss: number | null; /** Per-epoch validation scores (empty when earlyStopping is off). */ validationScores: number[]; bestValidationScore: number | null; } /** * Minibatch training loop shared by both MLPs — a faithful port of sklearn's * `_fit_stochastic`, except that the early-stopping split is a plain * deterministic TAIL split (last validationFraction of the rows) instead of * sklearn's shuffled/stratified `train_test_split`. * * `Y` is the already-encoded target matrix (one-hot / 0-1 column / raw * column), one row per sample of `X`. */ export declare function trainMLP(X: number[][], Y: number[][], params: MLPParams, config: MLPTrainConfig): MLPTrainResult;