import { SublinearSolver } from '../../core/solver.js';
import { MatrixOperations } from '../../core/matrix.js';
import { SolverError } from '../../core/types.js';
import { OptimizedSolverTools } from './solver-optimized.js';
import { WasmSublinearSolverTools } from './wasm-sublinear-solver.js';
export class SolverTools {
static wasmSolver = null;
static getWasmSolver() {
if (!this.wasmSolver) {
this.wasmSolver = new WasmSublinearSolverTools();
}
return this.wasmSolver;
}
static shouldUseOptimizedSolver(params) {
if (params.useOptimized === true) {
return true;
}
if (params.matrix?.format === 'dense') {
return true;
}
if (params.matrix?.rows > 500 || params.matrix?.cols > 500) {
return true;
}
if (Array.isArray(params.matrix) && Array.isArray(params.matrix[0])) {
return true;
}
if (params.matrix?.data && !params.matrix?.format) {
return true;
}
return false;
}
static async solve(params) {
try {
const wasmSolver = new WasmSublinearSolverTools();
if (wasmSolver.isEnhancedWasmAvailable()) {
console.log('🚀 Using O(log n) WASM solver with Johnson-Lindenstrauss embedding');
let matrix;
if (params.matrix.format === 'dense' && Array.isArray(params.matrix.data)) {
matrix = params.matrix.data;
}
else if (Array.isArray(params.matrix) && Array.isArray(params.matrix[0])) {
matrix = params.matrix;
}
else {
throw new Error('Matrix format not supported for WASM solver');
}
return await wasmSolver.solveSublinear(matrix, params.vector);
}
}
catch (error) {
console.warn('⚠️ O(log n) WASM solver failed, falling back:', error.message);
}
const needsOptimization = this.shouldUseOptimizedSolver(params);
if (needsOptimization) {
return OptimizedSolverTools.solve(params);
}
try {
if (!params.matrix) {
throw new SolverError('Matrix parameter is required', 'INVALID_PARAMETERS');
}
if (!params.vector) {
throw new SolverError('Vector parameter is required', 'INVALID_PARAMETERS');
}
if (!Array.isArray(params.vector)) {
throw new SolverError('Vector must be an array of numbers', 'INVALID_PARAMETERS');
}
const config = {
method: params.method || 'neumann',
epsilon: params.epsilon || 1e-6,
maxIterations: params.maxIterations || 5000, timeout: params.timeout || 30000, enableProgress: false
};
MatrixOperations.validateMatrix(params.matrix);
if (params.vector.length !== params.matrix.rows) {
throw new SolverError(`Vector length ${params.vector.length} does not match matrix rows ${params.matrix.rows}`, 'INVALID_DIMENSIONS');
}
const solver = new SublinearSolver(config);
const result = await solver.solve(params.matrix, params.vector);
return {
solution: result.solution,
iterations: result.iterations,
residual: result.residual,
converged: result.converged,
method: result.method,
computeTime: result.computeTime,
memoryUsed: result.memoryUsed,
efficiency: {
convergenceRate: result.iterations > 0 ? Math.pow(result.residual, 1 / result.iterations) : 1,
timePerIteration: result.computeTime / Math.max(1, result.iterations),
memoryEfficiency: result.memoryUsed / (params.matrix.rows * params.matrix.cols)
},
metadata: {
matrixSize: { rows: params.matrix.rows, cols: params.matrix.cols },
configUsed: config,
timestamp: new Date().toISOString()
}
};
}
catch (error) {
if (error instanceof SolverError) {
throw error;
}
throw new SolverError(`Solve operation failed: ${error instanceof Error ? error.message : String(error)}`, 'INTERNAL_ERROR', { originalError: error });
}
}
static async estimateEntry(params) {
try {
if (!params.matrix) {
throw new SolverError('Matrix parameter is required', 'INVALID_PARAMETERS');
}
if (!params.vector) {
throw new SolverError('Vector parameter is required', 'INVALID_PARAMETERS');
}
if (!Array.isArray(params.vector)) {
throw new SolverError('Vector must be an array of numbers', 'INVALID_PARAMETERS');
}
if (typeof params.row !== 'number' || !Number.isInteger(params.row)) {
throw new SolverError('Row must be a valid integer', 'INVALID_PARAMETERS');
}
if (typeof params.column !== 'number' || !Number.isInteger(params.column)) {
throw new SolverError('Column must be a valid integer', 'INVALID_PARAMETERS');
}
MatrixOperations.validateMatrix(params.matrix);
if (params.row < 0 || params.row >= params.matrix.rows) {
throw new SolverError(`Row index ${params.row} out of bounds. Matrix has ${params.matrix.rows} rows (valid range: 0-${params.matrix.rows - 1})`, 'INVALID_PARAMETERS');
}
if (params.column < 0 || params.column >= params.matrix.cols) {
throw new SolverError(`Column index ${params.column} out of bounds. Matrix has ${params.matrix.cols} columns (valid range: 0-${params.matrix.cols - 1})`, 'INVALID_PARAMETERS');
}
if (params.vector.length !== params.matrix.rows) {
throw new SolverError(`Vector length ${params.vector.length} does not match matrix rows ${params.matrix.rows}`, 'INVALID_DIMENSIONS');
}
const solverConfig = {
method: 'random-walk',
epsilon: params.epsilon || 1e-6,
maxIterations: 2000, timeout: 15000, enableProgress: false
};
const solver = new SublinearSolver(solverConfig);
const estimationConfig = {
row: params.row,
column: params.column,
epsilon: params.epsilon || 1e-6,
confidence: params.confidence || 0.95,
method: params.method || 'random-walk'
};
const result = await solver.estimateEntry(params.matrix, params.vector, estimationConfig);
const standardError = Math.sqrt(result.variance);
const marginOfError = 1.96 * standardError; return {
estimate: result.estimate,
variance: result.variance,
confidence: result.confidence,
standardError,
confidenceInterval: {
lower: result.estimate - marginOfError,
upper: result.estimate + marginOfError
},
row: params.row,
column: params.column,
method: estimationConfig.method,
metadata: {
matrixSize: { rows: params.matrix.rows, cols: params.matrix.cols },
configUsed: estimationConfig,
timestamp: new Date().toISOString()
}
};
}
catch (error) {
if (error instanceof SolverError) {
throw error;
}
throw new SolverError(`Entry estimation failed: ${error instanceof Error ? error.message : String(error)}`, 'INTERNAL_ERROR', {
row: params.row,
column: params.column,
originalError: error
});
}
}
static async *streamingSolve(params, progressCallback) {
const config = {
method: params.method || 'neumann',
epsilon: params.epsilon || 1e-6,
maxIterations: params.maxIterations || 1000,
timeout: params.timeout,
enableProgress: true
};
const solver = new SublinearSolver(config);
let iterationCount = 0;
const startTime = Date.now();
const callback = (progress) => {
iterationCount++;
const streamProgress = {
...progress,
percentage: Math.min(100, (iterationCount / config.maxIterations) * 100),
elapsedTime: Date.now() - startTime,
estimatedRemaining: progress.estimated
};
if (progressCallback) {
progressCallback(streamProgress);
}
return streamProgress;
};
try {
const result = await solver.solve(params.matrix, params.vector, callback);
yield {
type: 'final',
result,
totalIterations: iterationCount,
totalTime: Date.now() - startTime
};
}
catch (error) {
yield {
type: 'error',
error: error instanceof Error ? error.message : 'Unknown error',
iterations: iterationCount,
elapsedTime: Date.now() - startTime
};
}
}
static async batchSolve(matrix, vectors, params = {}) {
const config = {
method: params.method || 'neumann',
epsilon: params.epsilon || 1e-6,
maxIterations: params.maxIterations || 1000,
timeout: params.timeout,
enableProgress: false
};
const solver = new SublinearSolver(config);
const results = [];
for (let i = 0; i < vectors.length; i++) {
const result = await solver.solve(matrix, vectors[i]);
results.push({
index: i,
...result
});
}
return {
results,
summary: {
totalSystems: vectors.length,
averageIterations: results.reduce((sum, r) => sum + r.iterations, 0) / results.length,
averageTime: results.reduce((sum, r) => sum + r.computeTime, 0) / results.length,
allConverged: results.every(r => r.converged),
convergenceRate: results.filter(r => r.converged).length / results.length
}
};
}
}