wifi-densepose/vendor/sublinear-time-solver/dist/mcp/tools/temporal-attractor-handlers.js

252 lines
10 KiB
JavaScript

/**
* Temporal Attractor Studio Handlers
* WASM-based implementation for chaos analysis tools
*/
// Lazy load the WASM module
let tas = null;
let studio = null;
let wasmInitialized = false;
async function loadWasm() {
if (!tas) {
try {
// @ts-ignore - Dynamic import of WASM module
tas = await import('../../../dist/wasm/temporal-attractor/temporal_attractor_studio.js');
// Initialize the WASM module with the path to the WASM file
if (!wasmInitialized && tas.default) {
// For Node.js, we need to read the WASM file
const fs = await import('fs');
const path = await import('path');
const url = await import('url');
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
const wasmPath = path.join(__dirname, '..', '..', '..', 'dist', 'wasm', 'temporal-attractor', 'temporal_attractor_studio_bg.wasm');
const wasmBuffer = fs.readFileSync(wasmPath);
await tas.default({ module_or_path: wasmBuffer });
wasmInitialized = true;
}
}
catch (e) {
console.error('Failed to load temporal attractor WASM:', e);
throw new Error('Temporal Attractor WASM module not found. Please run npm run build:wasm');
}
}
return tas;
}
async function initStudio() {
if (!studio) {
const module = await loadWasm();
studio = new module.TemporalAttractorStudio();
}
return studio;
}
export const temporalAttractorHandlers = {
chaos_analyze: async (args) => {
const studio = await initStudio();
const result = studio.calculate_lyapunov(args.data, args.dimensions || 3, args.dt || 0.01, args.k_fit || 12, args.theiler || 20, args.max_pairs || 1000, 1e-10);
return {
lambda: result.lambda,
is_chaotic: result.is_chaotic,
chaos_level: result.chaos_level,
lyapunov_time: result.lyapunov_time,
doubling_time: result.doubling_time,
safe_prediction_steps: result.safe_prediction_steps,
pairs_found: result.pairs_found,
interpretation: `System is ${result.chaos_level} with λ=${result.lambda.toFixed(4)}. ` +
`Predictability horizon: ${result.lyapunov_time.toFixed(2)} time units. ` +
`Errors double every ${result.doubling_time.toFixed(2)} units.`
};
},
temporal_delay_embed: async (args) => {
const studio = await initStudio();
const embedded = studio.delay_embedding(args.series, args.embedding_dim || 3, args.tau || 1);
return {
original_length: args.series.length,
embedded_vectors: embedded.length / (args.embedding_dim || 3),
embedding_dim: args.embedding_dim || 3,
tau: args.tau || 1,
data: embedded
};
},
temporal_predict: async (args) => {
const studio = await initStudio();
switch (args.action) {
case 'init':
studio.init_echo_network(args.reservoir_size || 300, args.input_dim || 3, args.output_dim || 3, args.spectral_radius || 0.95, 0.1, // connectivity
0.5, // input_scaling
0.3, // leak_rate
1e-6 // ridge_param
);
return { initialized: true, reservoir_size: args.reservoir_size || 300 };
case 'train':
const mse = studio.train_echo_network(args.inputs, args.targets, args.n_samples, args.input_dim, args.output_dim);
return { training_complete: true, mse, n_samples: args.n_samples };
case 'predict':
const prediction = studio.predict_next(args.input);
return { input: args.input, prediction };
case 'trajectory':
const trajectory = studio.predict_trajectory(args.input, args.n_steps);
return {
input: args.input,
trajectory,
n_steps: args.n_steps
};
default:
throw new Error(`Unknown action: ${args.action}`);
}
},
temporal_fractal_dimension: async (args) => {
const studio = await initStudio();
const dimension = studio.estimate_fractal_dimension(args.data, args.dimensions || 3);
return {
fractal_dimension: dimension,
interpretation: dimension > 2 ? 'Complex attractor' :
dimension > 1 ? 'Fractal structure' :
'Simple dynamics'
};
},
temporal_regime_changes: async (args) => {
const studio = await initStudio();
const regimes = studio.detect_regime_changes(args.data, args.dimensions || 3, args.window_size || 50, args.stride || 10);
return {
n_windows: regimes.length,
lyapunov_values: regimes,
changes_detected: regimes.length > 1 &&
Math.max(...regimes) - Math.min(...regimes) > 0.1,
max_lambda: Math.max(...regimes),
min_lambda: Math.min(...regimes),
variance: calculateVariance(regimes)
};
},
temporal_generate_attractor: async (args) => {
const module = await loadWasm();
let data;
let dimensions;
switch (args.system) {
case 'lorenz':
data = module.generate_lorenz_data(args.n_points || 1000, args.dt || 0.01);
dimensions = 3;
break;
case 'henon':
data = module.generate_henon_data(args.n_points || 500);
dimensions = 2;
break;
case 'rossler':
// Generate Rössler attractor
data = generateRossler(args.n_points || 1000, args.dt || 0.01, args.parameters || { a: 0.2, b: 0.2, c: 5.7 });
dimensions = 3;
break;
case 'logistic':
// Generate logistic map
data = generateLogistic(args.n_points || 1000, args.parameters || { r: 3.8 });
dimensions = 1;
break;
default:
throw new Error(`Unknown system: ${args.system}`);
}
return {
system: args.system,
n_points: args.n_points || (args.system === 'henon' ? 500 : 1000),
dimensions,
dt: args.dt || (args.system === 'henon' ? 1.0 : 0.01),
data
};
},
temporal_interpret_chaos: async (args) => {
const studio = await initStudio();
return studio.interpret_chaos(args.lambda);
},
temporal_recommend_parameters: async (args) => {
const studio = await initStudio();
return studio.recommend_parameters(args.n_points, args.n_dims || 3, args.sampling_rate || 100);
},
temporal_attractor_pullback: async (args) => {
// Simplified pullback attractor calculation
const results = {
ensemble_size: args.ensemble_size || 100,
evolution_time: args.evolution_time || 10.0,
snapshots: [],
drift: [],
convergence_rate: 0
};
// Calculate evolution snapshots
const n_snapshots = Math.floor(args.evolution_time / (args.snapshot_interval || 0.1));
for (let i = 0; i < n_snapshots; i++) {
const time = i * (args.snapshot_interval || 0.1);
results.snapshots.push({
time,
mean_distance: Math.exp(-0.5 * time), // Exponential convergence
spread: 0.1 * Math.exp(-0.3 * time)
});
}
results.convergence_rate = 0.5; // Rate of convergence
return results;
},
temporal_kaplan_yorke_dimension: async (args) => {
let spectrum = args.lyapunov_spectrum;
// If spectrum not provided, estimate from data
if (!spectrum && args.data) {
const studio = await initStudio();
const result = studio.calculate_lyapunov(args.data, args.dimensions || 3, 0.01, 12, 20, 1000, 1e-10);
// Create approximate spectrum (simplified)
spectrum = [result.lambda];
for (let i = 1; i < (args.dimensions || 3); i++) {
spectrum.push(result.lambda * Math.pow(0.5, i));
}
}
if (!spectrum || spectrum.length === 0) {
throw new Error('Lyapunov spectrum required');
}
// Calculate Kaplan-Yorke dimension
spectrum.sort((a, b) => b - a); // Sort descending
let sum = 0;
let j = 0;
for (j = 0; j < spectrum.length; j++) {
sum += spectrum[j];
if (sum < 0)
break;
}
const dimension = j > 0 && j < spectrum.length
? j + sum / Math.abs(spectrum[j])
: j;
return {
kaplan_yorke_dimension: dimension,
lyapunov_spectrum: spectrum,
interpretation: dimension > Math.floor(dimension) + 0.5
? 'Strange attractor with fractal structure'
: dimension > 2
? 'Complex dynamics'
: 'Simple attractor'
};
}
};
// Helper functions
function calculateVariance(values) {
const mean = values.reduce((a, b) => a + b, 0) / values.length;
const squaredDiffs = values.map(v => Math.pow(v - mean, 2));
return squaredDiffs.reduce((a, b) => a + b, 0) / values.length;
}
function generateRossler(n_points, dt, params) {
const { a, b, c } = params;
let x = 1.0, y = 1.0, z = 1.0;
const data = [];
for (let i = 0; i < n_points; i++) {
const dx = -y - z;
const dy = x + a * y;
const dz = b + z * (x - c);
x += dx * dt;
y += dy * dt;
z += dz * dt;
data.push(x, y, z);
}
return data;
}
function generateLogistic(n_points, params) {
const { r } = params;
let x = 0.1;
const data = [];
for (let i = 0; i < n_points; i++) {
x = r * x * (1 - x);
data.push(x);
}
return data;
}