UNPKG

@astermind/astermind-premium

Version:

Astermind Premium - Premium ML Toolkit

168 lines 6.08 kB
// time-series-elm.ts — Time-Series ELM for temporal pattern recognition // Sequence-to-sequence ELM with temporal dependencies import { ELM } from '@astermind/astermind-elm'; import { requireLicense } from '../core/license.js'; /** * Time-Series ELM for temporal pattern recognition * Features: * - Temporal pattern recognition * - Optional recurrent connections * - Sequence-to-sequence prediction * - Forecasting capabilities */ export class TimeSeriesELM { constructor(options) { this.history = []; // Store recent history for recurrent mode this.trained = false; requireLicense(); // Premium feature - requires valid license this.categories = options.categories; this.options = { categories: options.categories, hiddenUnits: options.hiddenUnits ?? 256, sequenceLength: options.sequenceLength ?? 10, lookbackWindow: options.lookbackWindow ?? 5, useRecurrent: options.useRecurrent ?? false, activation: options.activation ?? 'relu', maxLen: options.maxLen ?? 100, useTokenizer: options.useTokenizer ?? true, }; this.elm = new ELM({ useTokenizer: this.options.useTokenizer ? true : undefined, hiddenUnits: this.options.hiddenUnits, categories: this.options.categories, maxLen: this.options.maxLen, activation: this.options.activation, }); } /** * Train on time-series data * @param X Sequences of features (each element is a time step) * @param y Labels for each sequence */ train(X, y) { // Prepare labels const labelIndices = y.map(label => typeof label === 'number' ? label : this.options.categories.indexOf(label)); // Flatten sequences to features const flattenedFeatures = this._flattenSequences(X); // Train base ELM this.elm.setCategories?.(this.options.categories); this.elm.trainFromData?.(flattenedFeatures, labelIndices); this.trained = true; } /** * Train on single sequences (convenience method) */ trainSequences(sequences, labels) { this.train(sequences, labels); } /** * Predict from time-series sequence */ predict(sequence, topK = 3) { if (!this.trained) { throw new Error('Model must be trained before prediction'); } const sequences = Array.isArray(sequence[0][0]) ? sequence : [sequence]; const allResults = []; for (const seq of sequences) { // Flatten sequence to features const features = this._flattenSequence(seq); // Update history if using recurrent mode if (this.options.useRecurrent) { this._updateHistory(features); // Use history-enhanced features const enhancedFeatures = this._enhanceWithHistory(features); const preds = this.elm.predictFromVector?.([enhancedFeatures], topK) || []; allResults.push(...preds.map((p) => ({ label: p.label || this.options.categories[p.index || 0], prob: p.prob || 0, }))); } else { const preds = this.elm.predictFromVector?.([features], topK) || []; allResults.push(...preds.map((p) => ({ label: p.label || this.options.categories[p.index || 0], prob: p.prob || 0, }))); } } return allResults; } /** * Forecast future values (for regression/forecasting tasks) */ forecast(sequence, steps = 1) { if (!this.trained) { throw new Error('Model must be trained before forecasting'); } const forecasts = []; let currentSeq = [...sequence]; for (let step = 0; step < steps; step++) { const features = this._flattenSequence(currentSeq); const pred = this.elm.predictLogitsFromVector?.(features) || []; // Use prediction as next step (simplified - in practice, you'd have a regression head) forecasts.push([...pred]); // Update sequence for next step currentSeq.push(pred); if (currentSeq.length > this.options.sequenceLength) { currentSeq.shift(); } } return forecasts; } /** * Flatten sequences to feature vectors */ _flattenSequences(sequences) { return sequences.map(seq => this._flattenSequence(seq)); } /** * Flatten a single sequence */ _flattenSequence(sequence) { // Concatenate all time steps const flattened = []; // Take last lookbackWindow steps const relevantSteps = sequence.slice(-this.options.lookbackWindow); for (const step of relevantSteps) { flattened.push(...step); } // Pad if necessary while (flattened.length < this.options.lookbackWindow * (sequence[0]?.length || 1)) { flattened.push(0); } return flattened; } /** * Update history for recurrent mode */ _updateHistory(features) { this.history.push([...features]); // Keep only recent history if (this.history.length > this.options.lookbackWindow) { this.history.shift(); } } /** * Enhance features with history (recurrent mode) */ _enhanceWithHistory(currentFeatures) { if (this.history.length === 0) { return currentFeatures; } // Concatenate history with current features const historyFeatures = this.history.flat(); return [...historyFeatures, ...currentFeatures]; } /** * Clear history (useful for new sequences) */ clearHistory() { this.history = []; } } //# sourceMappingURL=time-series-elm.js.map