# WASM Integration Plan - Sublinear Time Solver ## Overview This plan outlines the comprehensive WebAssembly (WASM) integration strategy for the sublinear-time-solver project, focusing on optimal Rust-to-JavaScript bindings, streaming solutions, and performance optimization. ## 1. WASM Build Pipeline ### 1.1 wasm-pack Configuration Create `wasm-pack` configuration in `Cargo.toml`: ```toml [package.metadata.wasm-pack.profile.release] wee_alloc = false debug_assertions = false overflow_checks = false lto = true panic = "abort" codegen_units = 1 opt_level = "s" [package.metadata.wasm-pack.profile.dev] debug_assertions = true overflow_checks = true opt_level = 0 ``` ### 1.2 Build Targets Support multiple targets with conditional builds: ```bash # Browser ES modules (bundler) wasm-pack build --target bundler --out-dir pkg/bundler # Node.js CommonJS wasm-pack build --target nodejs --out-dir pkg/nodejs # Web (no bundler) wasm-pack build --target web --out-dir pkg/web # Universal (UMD) wasm-pack build --target no-modules --out-dir pkg/umd ``` ### 1.3 Optimization Flags **Cargo.toml profile optimizations:** ```toml [profile.release] opt-level = "s" # Optimize for size lto = true # Link-time optimization codegen-units = 1 # Single codegen unit for better optimization panic = "abort" # Smaller binary size strip = true # Strip debug symbols [features] default = ["simd"] simd = ["wide"] # Enable SIMD optimizations parallel = ["rayon"] # Parallel processing support ``` ### 1.4 Binary Size Optimization ```toml # Cargo.toml [dependencies] wee_alloc = { version = "0.4", optional = true } [features] wee_alloc = ["wee_alloc/static_array_backend"] ``` **Build script optimization:** ```bash #!/bin/bash # scripts/build-wasm.sh # Enable SIMD and optimize export RUSTFLAGS="-C target-feature=+simd128 -C opt-level=s" # Build with size optimization wasm-pack build \ --target bundler \ --out-dir pkg \ --features "simd" \ -- --no-default-features # Optimize WASM binary wasm-opt -Oz -o pkg/solver_bg.wasm pkg/solver_bg.wasm # Generate multiple targets for target in nodejs web no-modules; do wasm-pack build --target $target --out-dir "pkg/$target" done ``` ### 1.5 SIMD Enablement ```rust // src/simd.rs use std::simd::f64x8; #[cfg(target_feature = "simd128")] pub fn simd_matrix_multiply(a: &[f64], b: &[f64], result: &mut [f64]) { // SIMD-optimized matrix operations let chunks_a = a.chunks_exact(8); let chunks_b = b.chunks_exact(8); for ((chunk_a, chunk_b), result_chunk) in chunks_a.zip(chunks_b).zip(result.chunks_exact_mut(8)) { let va = f64x8::from_slice(chunk_a); let vb = f64x8::from_slice(chunk_b); let vr = va * vb; result_chunk.copy_from_slice(vr.as_array()); } } ``` ## 2. JavaScript Interface Design ### 2.1 TypeScript Definitions Structure ```typescript // types/index.d.ts export interface SolverConfig { maxIterations: number; tolerance: number; simdEnabled: boolean; streamChunkSize: number; } export interface Matrix { data: Float64Array; rows: number; cols: number; } export interface SolutionStep { iteration: number; residual: number; timestamp: number; convergence: boolean; } export class SublinearSolver { constructor(config?: Partial); // Synchronous solve solve(matrix: Matrix, vector: Float64Array): Float64Array; // Streaming solve solveStream(matrix: Matrix, vector: Float64Array): AsyncIterableIterator; // Batch operations solveBatch(problems: Array<{matrix: Matrix, vector: Float64Array}>): Promise; // Memory management dispose(): void; getMemoryUsage(): {used: number, capacity: number}; } export interface WasmModule { memory: WebAssembly.Memory; solver_new: (config_ptr: number) => number; solver_solve: (solver_ptr: number, matrix_ptr: number, vector_ptr: number) => number; solver_solve_stream: (solver_ptr: number, matrix_ptr: number, vector_ptr: number, callback_ptr: number) => void; solver_free: (solver_ptr: number) => void; } ``` ### 2.2 Async Initialization Patterns ```typescript // src/init.ts export async function initSolver(config?: Partial): Promise { // Dynamic import for better code splitting const wasmModule = await import('../pkg/solver'); await wasmModule.default(); // Initialize WASM module return new SublinearSolver(wasmModule, config); } // Lazy initialization pattern let solverPromise: Promise | null = null; export function getSolver(config?: Partial): Promise { if (!solverPromise) { solverPromise = initSolver(config); } return solverPromise; } ``` ### 2.3 Memory Management (SharedArrayBuffer) ```typescript // src/memory.ts export class WasmMemoryManager { private memory: WebAssembly.Memory; private allocations = new Map(); constructor(memory: WebAssembly.Memory) { this.memory = memory; } allocateFloat64Array(length: number): {ptr: number, view: Float64Array} { const bytes = length * 8; const ptr = this.allocate(bytes); const view = new Float64Array(this.memory.buffer, ptr, length); return {ptr, view}; } allocateSharedBuffer(length: number): {ptr: number, buffer: SharedArrayBuffer} { if (typeof SharedArrayBuffer === 'undefined') { throw new Error('SharedArrayBuffer not available'); } const bytes = length * 8; const buffer = new SharedArrayBuffer(bytes); const ptr = this.allocate(bytes); // Copy to WASM memory const wasmView = new Float64Array(this.memory.buffer, ptr, length); const sharedView = new Float64Array(buffer); wasmView.set(sharedView); return {ptr, buffer}; } private allocate(bytes: number): number { // Implementation depends on WASM allocator // This is a simplified version const ptr = (this.memory.buffer.byteLength); this.memory.grow(Math.ceil(bytes / 65536)); this.allocations.set(ptr, bytes); return ptr; } deallocate(ptr: number): void { this.allocations.delete(ptr); // Call WASM deallocator } } ``` ### 2.4 Error Handling Across Boundaries ```typescript // src/error-handling.ts export enum SolverErrorType { InvalidMatrix = 'INVALID_MATRIX', ConvergenceFailure = 'CONVERGENCE_FAILURE', MemoryError = 'MEMORY_ERROR', WasmError = 'WASM_ERROR' } export class SolverError extends Error { constructor( public type: SolverErrorType, message: string, public details?: any ) { super(message); this.name = 'SolverError'; } } // WASM error handler export function handleWasmError(errorCode: number, context: string): never { const errorMap = { 1: {type: SolverErrorType.InvalidMatrix, message: 'Matrix dimensions invalid'}, 2: {type: SolverErrorType.ConvergenceFailure, message: 'Failed to converge'}, 3: {type: SolverErrorType.MemoryError, message: 'Memory allocation failed'}, 99: {type: SolverErrorType.WasmError, message: 'Unknown WASM error'} }; const error = errorMap[errorCode] || errorMap[99]; throw new SolverError(error.type, `${error.message} in ${context}`, {errorCode}); } ``` ### 2.5 Stream Implementation (AsyncIterator) ```typescript // src/streaming.ts export class SolutionStream implements AsyncIterableIterator { private wasmSolver: number; private wasmModule: WasmModule; private buffer: SolutionStep[] = []; private isComplete = false; private error: Error | null = null; constructor(wasmSolver: number, wasmModule: WasmModule) { this.wasmSolver = wasmSolver; this.wasmModule = wasmModule; } async *[Symbol.asyncIterator](): AsyncIterableIterator { while (!this.isComplete && !this.error) { if (this.buffer.length > 0) { yield this.buffer.shift()!; } else { await this.waitForData(); } } if (this.error) { throw this.error; } // Yield remaining buffered items while (this.buffer.length > 0) { yield this.buffer.shift()!; } } async next(): Promise> { if (this.buffer.length > 0) { return {value: this.buffer.shift()!, done: false}; } if (this.isComplete) { return {value: undefined, done: true}; } if (this.error) { throw this.error; } await this.waitForData(); return this.next(); } private async waitForData(): Promise { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Stream timeout')); }, 10000); const checkData = () => { if (this.buffer.length > 0 || this.isComplete || this.error) { clearTimeout(timeout); resolve(); } else { setTimeout(checkData, 10); } }; checkData(); }); } // Called from WASM via callback onData(step: SolutionStep): void { this.buffer.push(step); } onComplete(): void { this.isComplete = true; } onError(error: Error): void { this.error = error; } } ``` ## 3. Data Transfer Optimization ### 3.1 Zero-Copy Strategies ```rust // src/lib.rs use wasm_bindgen::prelude::*; #[wasm_bindgen] pub struct MatrixView { data: Vec, rows: usize, cols: usize, } #[wasm_bindgen] impl MatrixView { #[wasm_bindgen(constructor)] pub fn new(rows: usize, cols: usize) -> MatrixView { MatrixView { data: vec![0.0; rows * cols], rows, cols, } } #[wasm_bindgen(getter)] pub fn data(&self) -> *const f64 { self.data.as_ptr() } #[wasm_bindgen(getter)] pub fn length(&self) -> usize { self.data.len() } // Zero-copy access to data #[wasm_bindgen] pub fn data_view(&self) -> js_sys::Float64Array { unsafe { js_sys::Float64Array::view(&self.data) } } // Set data without copying #[wasm_bindgen] pub fn set_data(&mut self, data: &[f64]) { self.data.copy_from_slice(data); } } ``` ### 3.2 Float64Array/Uint32Array Usage ```typescript // src/data-transfer.ts export class EfficientDataTransfer { private wasmModule: WasmModule; private memoryManager: WasmMemoryManager; transferMatrix(matrix: Matrix): number { // Use existing memory view if possible if (matrix.data.buffer === this.wasmModule.memory.buffer) { return matrix.data.byteOffset; } // Allocate and copy const {ptr, view} = this.memoryManager.allocateFloat64Array( matrix.rows * matrix.cols ); view.set(matrix.data); return ptr; } transferMatrixZeroCopy(matrix: Matrix): Float64Array { // Create view directly into WASM memory const wasmView = this.createWasmView(matrix.rows * matrix.cols); wasmView.set(matrix.data); return wasmView; } private createWasmView(length: number): Float64Array { const bytes = length * 8; const offset = this.wasmModule.memory.buffer.byteLength; // Grow memory if needed const pagesNeeded = Math.ceil(bytes / 65536); if (pagesNeeded > 0) { this.wasmModule.memory.grow(pagesNeeded); } return new Float64Array(this.wasmModule.memory.buffer, offset, length); } } ``` ### 3.3 Memory View Patterns ```typescript // src/memory-views.ts export class MemoryViewPool { private freeViews = new Map(); private inUseViews = new Set(); getView(length: number): Float64Array { const powerOf2 = Math.pow(2, Math.ceil(Math.log2(length))); const pool = this.freeViews.get(powerOf2) || []; let view = pool.pop(); if (!view) { view = new Float64Array(powerOf2); } this.inUseViews.add(view); return view.subarray(0, length); } releaseView(view: Float64Array): void { if (!this.inUseViews.has(view)) return; this.inUseViews.delete(view); const length = view.buffer.byteLength / 8; const pool = this.freeViews.get(length) || []; pool.push(view); this.freeViews.set(length, pool); } clear(): void { this.freeViews.clear(); this.inUseViews.clear(); } } ``` ### 3.4 Batch Operation Interfaces ```typescript // src/batch-operations.ts export interface BatchSolveRequest { id: string; matrix: Matrix; vector: Float64Array; priority?: number; } export interface BatchSolveResult { id: string; solution: Float64Array; iterations: number; error?: string; } export class BatchSolver { private requestQueue: BatchSolveRequest[] = []; private processing = false; async solveBatch(requests: BatchSolveRequest[]): Promise { // Sort by priority requests.sort((a, b) => (b.priority || 0) - (a.priority || 0)); // Batch allocate memory const totalMatrixElements = requests.reduce( (sum, req) => sum + req.matrix.rows * req.matrix.cols, 0 ); const totalVectorElements = requests.reduce( (sum, req) => sum + req.vector.length, 0 ); const matrixBuffer = new Float64Array(totalMatrixElements); const vectorBuffer = new Float64Array(totalVectorElements); // Copy data in batches let matrixOffset = 0; let vectorOffset = 0; const batchInfo = requests.map(req => { const matrixStart = matrixOffset; const vectorStart = vectorOffset; matrixBuffer.set(req.matrix.data, matrixOffset); vectorBuffer.set(req.vector, vectorOffset); matrixOffset += req.matrix.data.length; vectorOffset += req.vector.length; return { id: req.id, matrixStart, matrixLength: req.matrix.data.length, vectorStart, vectorLength: req.vector.length, rows: req.matrix.rows, cols: req.matrix.cols }; }); // Call WASM batch solver return this.callWasmBatchSolver(matrixBuffer, vectorBuffer, batchInfo); } private async callWasmBatchSolver( matrices: Float64Array, vectors: Float64Array, batchInfo: any[] ): Promise { // Implementation calls WASM batch processing function // Returns processed results return []; } } ``` ### 3.5 Callback vs Polling Approaches ```typescript // src/communication-patterns.ts export class CallbackBasedSolver { private callbacks = new Map void>(); solveWithCallback( matrix: Matrix, vector: Float64Array, onProgress: (step: SolutionStep) => void, onComplete: (solution: Float64Array) => void, onError: (error: Error) => void ): void { const callbackId = Math.random().toString(36); this.callbacks.set(`progress_${callbackId}`, onProgress); this.callbacks.set(`complete_${callbackId}`, onComplete); this.callbacks.set(`error_${callbackId}`, onError); // Call WASM with callback ID this.wasmModule.solver_solve_with_callback( this.solver, this.transferMatrix(matrix), this.transferVector(vector), callbackId ); } // Called from WASM handleCallback(callbackId: string, type: string, data: any): void { const callback = this.callbacks.get(`${type}_${callbackId}`); if (callback) { callback(data); if (type === 'complete' || type === 'error') { // Cleanup callbacks this.callbacks.delete(`progress_${callbackId}`); this.callbacks.delete(`complete_${callbackId}`); this.callbacks.delete(`error_${callbackId}`); } } } } export class PollingBasedSolver { private activeJobs = new Map(); async solveWithPolling(matrix: Matrix, vector: Float64Array): Promise { const jobId = Math.random().toString(36); // Start solving this.wasmModule.solver_solve_async( this.solver, this.transferMatrix(matrix), this.transferVector(vector), jobId ); // Poll for completion return new Promise((resolve, reject) => { const poll = () => { const status = this.wasmModule.solver_get_status(jobId); switch (status.state) { case 'completed': resolve(status.result); break; case 'error': reject(new Error(status.error)); break; case 'running': setTimeout(poll, 10); break; } }; poll(); }); } } ``` ## 4. NPM Package Structure ``` package/ ├── package.json ├── index.js # Entry point ├── index.d.ts # TypeScript definitions ├── dist/ │ ├── browser/ # Browser-optimized build │ │ ├── index.js │ │ ├── index.d.ts │ │ └── solver.wasm │ ├── node/ # Node.js optimized build │ │ ├── index.js │ │ ├── index.d.ts │ │ └── solver.wasm │ ├── web/ # Direct web usage │ │ ├── index.js │ │ ├── index.d.ts │ │ └── solver.wasm │ └── types/ # TypeScript definitions │ ├── index.d.ts │ ├── solver.d.ts │ └── streaming.d.ts ├── wasm/ # WASM binaries │ ├── solver_bg.wasm │ ├── solver.js │ └── solver.d.ts ├── src/ # Source TypeScript │ ├── index.ts │ ├── solver.ts │ ├── streaming.ts │ └── memory.ts ├── bin/ # CLI tools │ └── cli.js ├── examples/ # Usage examples │ ├── browser.html │ ├── node.js │ └── streaming.js └── bench/ # Benchmarks ├── performance.js └── memory.js ``` ### package.json Configuration ```json { "name": "sublinear-time-solver", "version": "1.0.0", "description": "High-performance WebAssembly linear algebra solver", "main": "dist/node/index.js", "module": "dist/browser/index.js", "browser": "dist/browser/index.js", "types": "dist/types/index.d.ts", "exports": { ".": { "browser": "./dist/browser/index.js", "node": "./dist/node/index.js", "import": "./dist/browser/index.js", "require": "./dist/node/index.js", "types": "./dist/types/index.d.ts" }, "./wasm": { "browser": "./wasm/solver.js", "node": "./wasm/solver.js", "types": "./wasm/solver.d.ts" } }, "files": [ "dist/", "wasm/", "bin/", "index.js", "index.d.ts" ], "bin": { "sublinear-solver": "./bin/cli.js" }, "scripts": { "build": "npm run build:wasm && npm run build:js", "build:wasm": "./scripts/build-wasm.sh", "build:js": "tsc && webpack", "test": "jest", "bench": "node bench/performance.js", "prepare": "npm run build" }, "dependencies": { "@types/node": "^18.0.0" }, "devDependencies": { "wasm-pack": "^0.12.0", "typescript": "^5.0.0", "webpack": "^5.0.0", "jest": "^29.0.0" }, "engines": { "node": ">=16.0.0" }, "repository": { "type": "git", "url": "https://github.com/your-org/sublinear-time-solver" } } ``` ## 5. Streaming Solution Design ### 5.1 AsyncIterator Implementation ```typescript // src/streaming/async-iterator.ts export class StreamingSolver implements AsyncIterable { private controller: ReadableStreamDefaultController | null = null; private stream: ReadableStream | null = null; async *solve(matrix: Matrix, vector: Float64Array): AsyncIterableIterator { const stream = this.createSolutionStream(matrix, vector); const reader = stream.getReader(); try { while (true) { const {done, value} = await reader.read(); if (done) break; yield value; } } finally { reader.releaseLock(); } } private createSolutionStream(matrix: Matrix, vector: Float64Array): ReadableStream { return new ReadableStream({ start: (controller) => { this.controller = controller; this.startWasmSolver(matrix, vector); }, cancel: () => { this.stopWasmSolver(); } }); } private startWasmSolver(matrix: Matrix, vector: Float64Array): void { // Transfer data to WASM const matrixPtr = this.transferMatrix(matrix); const vectorPtr = this.transferVector(vector); // Start streaming solve this.wasmModule.solver_solve_stream( this.solver, matrixPtr, vectorPtr, this.createStreamCallback() ); } private createStreamCallback(): number { // Create callback that WASM can call const callback = (step: SolutionStep) => { if (this.controller) { this.controller.enqueue(step); if (step.convergence) { this.controller.close(); } } }; return this.registerCallback(callback); } } ``` ### 5.2 Chunked Computation Strategy ```rust // src/streaming.rs use wasm_bindgen::prelude::*; use std::sync::Mutex; #[wasm_bindgen] pub struct StreamingSolver { config: SolverConfig, state: Mutex, } #[wasm_bindgen] impl StreamingSolver { #[wasm_bindgen(constructor)] pub fn new(chunk_size: usize) -> StreamingSolver { StreamingSolver { config: SolverConfig { chunk_size }, state: Mutex::new(SolverState::new()), } } #[wasm_bindgen] pub fn solve_chunked( &self, matrix_ptr: *const f64, matrix_rows: usize, matrix_cols: usize, vector_ptr: *const f64, vector_len: usize, callback: &js_sys::Function, ) { let matrix = unsafe { std::slice::from_raw_parts(matrix_ptr, matrix_rows * matrix_cols) }; let vector = unsafe { std::slice::from_raw_parts(vector_ptr, vector_len) }; let mut state = self.state.lock().unwrap(); state.initialize(matrix, vector); // Process in chunks while !state.is_converged() && state.iteration < self.config.max_iterations { let chunk_result = self.process_chunk(&mut state); // Create solution step let step = SolutionStep { iteration: state.iteration, residual: chunk_result.residual, timestamp: js_sys::Date::now(), convergence: chunk_result.converged, }; // Call JavaScript callback let step_obj = serde_wasm_bindgen::to_value(&step).unwrap(); callback.call1(&JsValue::NULL, &step_obj).unwrap(); if chunk_result.converged { break; } // Yield control back to JavaScript event loop self.yield_control(); } } fn process_chunk(&self, state: &mut SolverState) -> ChunkResult { // Process one chunk of iterations for _ in 0..self.config.chunk_size { state.iteration += 1; // Perform one iteration step let residual = self.conjugate_gradient_step(state); if residual < self.config.tolerance { return ChunkResult { residual, converged: true, }; } } ChunkResult { residual: state.current_residual, converged: false, } } fn yield_control(&self) { // Use setTimeout to yield control let closure = Closure::once(|| {}); web_sys::window() .unwrap() .set_timeout_with_callback_and_timeout_and_arguments_0( closure.as_ref().unchecked_ref(), 0, ) .unwrap(); closure.forget(); } } ``` ### 5.3 Event Emitter Patterns ```typescript // src/streaming/event-emitter.ts export class SolverEventEmitter extends EventTarget { solve(matrix: Matrix, vector: Float64Array): Promise { return new Promise((resolve, reject) => { this.addEventListener('progress', (event: CustomEvent) => { // Handle progress updates console.log(`Iteration ${event.detail.iteration}: residual=${event.detail.residual}`); }); this.addEventListener('complete', (event: CustomEvent) => { resolve(event.detail); }); this.addEventListener('error', (event: CustomEvent) => { reject(event.detail); }); // Start WASM solver with event callbacks this.startSolverWithEvents(matrix, vector); }); } private startSolverWithEvents(matrix: Matrix, vector: Float64Array): void { const progressCallback = (step: SolutionStep) => { this.dispatchEvent(new CustomEvent('progress', {detail: step})); }; const completeCallback = (solution: Float64Array) => { this.dispatchEvent(new CustomEvent('complete', {detail: solution})); }; const errorCallback = (error: Error) => { this.dispatchEvent(new CustomEvent('error', {detail: error})); }; this.wasmModule.solver_solve_with_events( this.solver, this.transferMatrix(matrix), this.transferVector(vector), this.registerCallback(progressCallback), this.registerCallback(completeCallback), this.registerCallback(errorCallback) ); } } ``` ### 5.4 Backpressure Handling ```typescript // src/streaming/backpressure.ts export class BackpressureController { private bufferSize: number; private highWaterMark: number; private lowWaterMark: number; private currentBufferSize = 0; private isPaused = false; constructor(bufferSize = 1000, highWaterMark = 0.8, lowWaterMark = 0.2) { this.bufferSize = bufferSize; this.highWaterMark = Math.floor(bufferSize * highWaterMark); this.lowWaterMark = Math.floor(bufferSize * lowWaterMark); } shouldPause(): boolean { return this.currentBufferSize >= this.highWaterMark; } shouldResume(): boolean { return this.currentBufferSize <= this.lowWaterMark; } addToBuffer(size: number): void { this.currentBufferSize += size; if (!this.isPaused && this.shouldPause()) { this.isPaused = true; this.pauseProducer(); } } removeFromBuffer(size: number): void { this.currentBufferSize = Math.max(0, this.currentBufferSize - size); if (this.isPaused && this.shouldResume()) { this.isPaused = false; this.resumeProducer(); } } private pauseProducer(): void { // Signal WASM to pause production this.wasmModule.solver_pause_streaming(); } private resumeProducer(): void { // Signal WASM to resume production this.wasmModule.solver_resume_streaming(); } } ``` ### 5.5 Progress Reporting ```typescript // src/streaming/progress.ts export interface ProgressInfo { percentage: number; estimatedTimeRemaining: number; currentIteration: number; totalIterations: number; residual: number; convergenceRate: number; } export class ProgressTracker { private startTime: number = 0; private iterations: number[] = []; private residuals: number[] = []; private maxHistory = 100; startTracking(): void { this.startTime = Date.now(); this.iterations = []; this.residuals = []; } updateProgress(step: SolutionStep): ProgressInfo { this.iterations.push(step.iteration); this.residuals.push(step.residual); // Keep only recent history if (this.iterations.length > this.maxHistory) { this.iterations.shift(); this.residuals.shift(); } const currentTime = Date.now(); const elapsedTime = currentTime - this.startTime; // Estimate convergence rate const convergenceRate = this.estimateConvergenceRate(); // Estimate total iterations needed const estimatedTotalIterations = this.estimateTotalIterations( step.residual, convergenceRate ); // Calculate progress percentage const percentage = Math.min( 100, (step.iteration / estimatedTotalIterations) * 100 ); // Estimate time remaining const iterationsPerMs = step.iteration / elapsedTime; const remainingIterations = Math.max(0, estimatedTotalIterations - step.iteration); const estimatedTimeRemaining = remainingIterations / iterationsPerMs; return { percentage, estimatedTimeRemaining, currentIteration: step.iteration, totalIterations: estimatedTotalIterations, residual: step.residual, convergenceRate, }; } private estimateConvergenceRate(): number { if (this.residuals.length < 2) return 0; const recent = this.residuals.slice(-10); if (recent.length < 2) return 0; // Calculate average reduction rate let totalRate = 0; for (let i = 1; i < recent.length; i++) { if (recent[i-1] > 0) { totalRate += recent[i] / recent[i-1]; } } return totalRate / (recent.length - 1); } private estimateTotalIterations(currentResidual: number, convergenceRate: number): number { if (convergenceRate >= 1 || convergenceRate <= 0) { return this.iterations[this.iterations.length - 1] * 2; // Conservative estimate } const targetResidual = 1e-10; // Target convergence const iterationsNeeded = Math.log(targetResidual / currentResidual) / Math.log(convergenceRate); return Math.max( this.iterations[this.iterations.length - 1], this.iterations[this.iterations.length - 1] + iterationsNeeded ); } } ``` ## 6. Performance Benchmarks ### 6.1 WASM vs Native Rust Comparison ```typescript // bench/wasm-vs-native.ts export class WasmNativeBenchmark { async runComparison(sizes: number[]): Promise { const results = { wasm: [], native: [], overhead: [] }; for (const size of sizes) { const matrix = this.generateMatrix(size, size); const vector = this.generateVector(size); // WASM benchmark const wasmTime = await this.benchmarkWasm(matrix, vector); results.wasm.push({size, time: wasmTime}); // Native Rust benchmark (via Node.js addon) const nativeTime = await this.benchmarkNative(matrix, vector); results.native.push({size, time: nativeTime}); // Calculate overhead const overhead = ((wasmTime - nativeTime) / nativeTime) * 100; results.overhead.push({size, overhead}); console.log(`Size ${size}: WASM=${wasmTime}ms, Native=${nativeTime}ms, Overhead=${overhead.toFixed(2)}%`); } return results; } private async benchmarkWasm(matrix: Matrix, vector: Float64Array): Promise { const solver = await this.createWasmSolver(); const start = performance.now(); const result = solver.solve(matrix, vector); const end = performance.now(); return end - start; } private async benchmarkNative(matrix: Matrix, vector: Float64Array): Promise { // This would call a native Node.js addon for comparison // Implementation depends on your native benchmark setup return 0; } } ``` ### 6.2 JS Overhead Measurement ```typescript // bench/js-overhead.ts export class JavaScriptOverheadBenchmark { async measureDataTransferOverhead(): Promise { const sizes = [100, 1000, 10000, 100000]; const results = []; for (const size of sizes) { const data = new Float64Array(size); for (let i = 0; i < size; i++) { data[i] = Math.random(); } // Measure direct WASM call const directTime = await this.measureDirectCall(data); // Measure with JS wrapper const wrapperTime = await this.measureWrapperCall(data); // Measure data copying const copyTime = await this.measureDataCopy(data); const overhead = { size, directTime, wrapperTime, copyTime, wrapperOverhead: ((wrapperTime - directTime) / directTime) * 100, copyOverhead: (copyTime / directTime) * 100 }; results.push(overhead); console.log(`Size ${size}: Direct=${directTime}ms, Wrapper=${wrapperTime}ms, Copy=${copyTime}ms`); } return {results, summary: this.calculateSummary(results)}; } private async measureDirectCall(data: Float64Array): Promise { const ptr = this.allocateWasmMemory(data.length); this.copyToWasmMemory(ptr, data); const start = performance.now(); this.wasmModule.direct_computation(ptr, data.length); const end = performance.now(); this.freeWasmMemory(ptr); return end - start; } private async measureWrapperCall(data: Float64Array): Promise { const start = performance.now(); this.solver.computeWithWrapper(data); const end = performance.now(); return end - start; } private async measureDataCopy(data: Float64Array): Promise { const start = performance.now(); const copy = new Float64Array(data); const end = performance.now(); return end - start; } } ``` ### 6.3 Memory Usage Profiling ```typescript // bench/memory-profiler.ts export class MemoryProfiler { private memorySnapshots: MemorySnapshot[] = []; async profileSolverMemory(matrix: Matrix, vector: Float64Array): Promise { this.startProfiling(); // Initialize solver this.takeSnapshot('initialization'); const solver = await this.createSolver(); this.takeSnapshot('solver_created'); // Transfer data const matrixPtr = solver.transferMatrix(matrix); this.takeSnapshot('matrix_transferred'); const vectorPtr = solver.transferVector(vector); this.takeSnapshot('vector_transferred'); // Solve const solution = await solver.solve(matrixPtr, vectorPtr); this.takeSnapshot('solution_complete'); // Cleanup solver.dispose(); this.takeSnapshot('cleanup_complete'); return this.generateProfile(); } private takeSnapshot(label: string): void { const snapshot = { label, timestamp: Date.now(), wasmMemory: this.getWasmMemoryUsage(), jsHeap: this.getJSHeapUsage(), totalMemory: performance.memory?.usedJSHeapSize || 0 }; this.memorySnapshots.push(snapshot); } private getWasmMemoryUsage(): number { return this.wasmModule.memory.buffer.byteLength; } private getJSHeapUsage(): number { return performance.memory?.usedJSHeapSize || 0; } private generateProfile(): MemoryProfile { const peak = Math.max(...this.memorySnapshots.map(s => s.totalMemory)); const growth = this.calculateMemoryGrowth(); const leaks = this.detectMemoryLeaks(); return { snapshots: this.memorySnapshots, peakUsage: peak, memoryGrowth: growth, potentialLeaks: leaks, recommendations: this.generateRecommendations() }; } } ``` ### 6.4 Streaming Latency Metrics ```typescript // bench/streaming-benchmark.ts export class StreamingLatencyBenchmark { async measureStreamingPerformance(): Promise { const matrix = this.generateLargeMatrix(10000, 10000); const vector = this.generateVector(10000); const metrics = { firstYield: 0, averageLatency: 0, throughput: 0, bufferUtilization: [], backpressureEvents: 0 }; const solver = await this.createStreamingSolver(); const startTime = performance.now(); let firstYield = true; let totalYields = 0; let totalLatency = 0; for await (const step of solver.solve(matrix, vector)) { const currentTime = performance.now(); if (firstYield) { metrics.firstYield = currentTime - startTime; firstYield = false; } // Measure latency between yields if (totalYields > 0) { const latency = currentTime - this.lastYieldTime; totalLatency += latency; } totalYields++; this.lastYieldTime = currentTime; // Track buffer utilization metrics.bufferUtilization.push(solver.getBufferUtilization()); // Count backpressure events if (solver.isBackpressureActive()) { metrics.backpressureEvents++; } } const totalTime = performance.now() - startTime; metrics.averageLatency = totalLatency / (totalYields - 1); metrics.throughput = totalYields / (totalTime / 1000); // yields per second return metrics; } } ``` ## Example TypeScript Usage ```typescript // examples/basic-usage.ts import { SublinearSolver, Matrix, initSolver } from 'sublinear-time-solver'; async function basicExample() { // Initialize solver const solver = await initSolver({ maxIterations: 1000, tolerance: 1e-10, simdEnabled: true, streamChunkSize: 100 }); // Create test matrix and vector const matrix: Matrix = { data: new Float64Array([4, 1, 1, 3]), rows: 2, cols: 2 }; const vector = new Float64Array([1, 2]); // Synchronous solve const solution = solver.solve(matrix, vector); console.log('Solution:', solution); // Streaming solve with progress tracking console.log('Streaming solve:'); for await (const step of solver.solveStream(matrix, vector)) { console.log(`Iteration ${step.iteration}: residual=${step.residual}`); if (step.convergence) { console.log('Converged!'); break; } } // Batch solving const problems = [ {matrix, vector}, {matrix: matrix, vector: new Float64Array([2, 3])}, {matrix: matrix, vector: new Float64Array([3, 4])} ]; const batchSolutions = await solver.solveBatch(problems); console.log('Batch solutions:', batchSolutions); // Memory usage console.log('Memory usage:', solver.getMemoryUsage()); // Cleanup solver.dispose(); } // Event-driven example async function eventDrivenExample() { const solver = await initSolver(); solver.addEventListener('progress', (event) => { console.log(`Progress: ${event.detail.percentage}%`); }); solver.addEventListener('complete', (event) => { console.log('Solution:', event.detail); }); const matrix: Matrix = { data: new Float64Array([...]), rows: 1000, cols: 1000 }; const vector = new Float64Array(1000); solver.solveAsync(matrix, vector); } basicExample().catch(console.error); ``` ## WASM-Bindgen Annotations ```rust // src/lib.rs use wasm_bindgen::prelude::*; // Enable console.log from Rust #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console)] fn log(s: &str); } macro_rules! console_log { ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) } #[wasm_bindgen] pub struct SublinearSolver { config: SolverConfig, state: Option, } #[wasm_bindgen] impl SublinearSolver { #[wasm_bindgen(constructor)] pub fn new(config: JsValue) -> Result { let config: SolverConfig = serde_wasm_bindgen::from_value(config) .map_err(|e| JsValue::from_str(&e.to_string()))?; Ok(SublinearSolver { config, state: None, }) } #[wasm_bindgen] pub fn solve( &mut self, matrix_data: &[f64], matrix_rows: usize, matrix_cols: usize, vector_data: &[f64], ) -> Result, JsValue> { // Validate input if matrix_data.len() != matrix_rows * matrix_cols { return Err(JsValue::from_str("Matrix dimensions mismatch")); } if vector_data.len() != matrix_rows { return Err(JsValue::from_str("Vector size mismatch")); } // Create matrix and vector views let matrix = Matrix::from_slice(matrix_data, matrix_rows, matrix_cols); let vector = Vector::from_slice(vector_data); // Solve system match self.conjugate_gradient_solve(&matrix, &vector) { Ok(solution) => Ok(solution.to_vec()), Err(e) => Err(JsValue::from_str(&e.to_string())), } } #[wasm_bindgen] pub fn solve_stream( &mut self, matrix_data: &[f64], matrix_rows: usize, matrix_cols: usize, vector_data: &[f64], progress_callback: &js_sys::Function, ) -> Result<(), JsValue> { let matrix = Matrix::from_slice(matrix_data, matrix_rows, matrix_cols); let vector = Vector::from_slice(vector_data); self.conjugate_gradient_stream(&matrix, &vector, |step| { let step_js = serde_wasm_bindgen::to_value(&step).unwrap(); progress_callback.call1(&JsValue::NULL, &step_js).unwrap(); })?; Ok(()) } #[wasm_bindgen(getter)] pub fn memory_usage(&self) -> JsValue { let usage = MemoryUsage { used: self.get_used_memory(), capacity: self.get_total_capacity(), }; serde_wasm_bindgen::to_value(&usage).unwrap() } #[wasm_bindgen] pub fn dispose(&mut self) { self.state = None; // Additional cleanup } } // Enable SIMD features #[wasm_bindgen] pub fn enable_simd() -> bool { cfg!(target_feature = "simd128") } // Memory management utilities #[wasm_bindgen] pub fn allocate_matrix(rows: usize, cols: usize) -> *mut f64 { let size = rows * cols; let layout = std::alloc::Layout::array::(size).unwrap(); unsafe { std::alloc::alloc(layout) as *mut f64 } } #[wasm_bindgen] pub fn deallocate_matrix(ptr: *mut f64, rows: usize, cols: usize) { let size = rows * cols; let layout = std::alloc::Layout::array::(size).unwrap(); unsafe { std::alloc::dealloc(ptr as *mut u8, layout) } } // Feature detection #[wasm_bindgen] pub fn get_features() -> JsValue { let features = Features { simd_enabled: cfg!(target_feature = "simd128"), parallel_enabled: cfg!(feature = "parallel"), memory_64: cfg!(target_pointer_width = "64"), }; serde_wasm_bindgen::to_value(&features).unwrap() } ``` ## Implementation Roadmap ### Phase 1: Core WASM Integration (Weeks 1-2) - [ ] Set up wasm-pack build pipeline - [ ] Implement basic Rust-to-JS bindings - [ ] Create TypeScript interface definitions - [ ] Basic memory management ### Phase 2: Performance Optimization (Weeks 3-4) - [ ] SIMD optimization implementation - [ ] Zero-copy data transfer patterns - [ ] Memory pooling and management - [ ] Build target optimization ### Phase 3: Streaming Implementation (Weeks 5-6) - [ ] AsyncIterator streaming interface - [ ] Chunked computation strategy - [ ] Backpressure handling - [ ] Progress reporting system ### Phase 4: NPM Package & Testing (Weeks 7-8) - [ ] Complete NPM package structure - [ ] Comprehensive test suite - [ ] Performance benchmarking - [ ] Documentation and examples ### Phase 5: Advanced Features (Weeks 9-10) - [ ] Batch operation interfaces - [ ] Event-driven patterns - [ ] CLI tool implementation - [ ] Browser compatibility testing This comprehensive WASM integration plan provides a solid foundation for building high-performance WebAssembly bindings for the sublinear-time-solver project, with focus on optimal performance, streaming capabilities, and excellent developer experience.