Ultra-fast MicroLoRA adaptation for WASM - rank-2 LoRA with <100us latency for per-operator learning.
npm install ruvector-learning-wasmThis package provides Low-Rank Adaptation (LoRA) matrices optimized for WebAssembly execution. It enables real-time per-operator-type learning in query optimization systems with minimal latency overhead.
- Rank-2 LoRA: Minimal parameter count (2d parameters per adapter)
- Per-Operator Scoping: Separate adapters for 17 different operator types
- <100us Adaptation: Instant weight updates for real-time learning
- WASM-Optimized: Compiled to WebAssembly for near-native performance
- Zero-Allocation Hot Paths: Pre-allocated buffers for performance-critical operations
The main LoRA engine for single-adapter use cases.
import init, { WasmMicroLoRA } from 'ruvector-learning-wasm';
// Initialize WASM module
await init();
// Create a new MicroLoRA engine
const lora = new WasmMicroLoRA(
256, // dim: Embedding dimension (max 256)
0.1, // alpha: Scaling factor
0.01 // learning_rate: Learning rate for adaptation
);
// Forward pass with typed array
const input = new Float32Array(256).fill(1.0);
const output = lora.forward_array(input);
// Adapt with gradient
const gradient = new Float32Array(256).fill(0.1);
lora.adapt_array(gradient);
// Get statistics
console.log('Forward count:', lora.forward_count());
console.log('Adapt count:', lora.adapt_count());
console.log('Delta norm:', lora.delta_norm());
console.log('Parameter count:', lora.param_count());
// Reset engine
lora.reset();For performance-critical loops, use the buffer-based API:
const lora = new WasmMicroLoRA(256, 0.1, 0.01);
// Get buffer pointers
const inputPtr = lora.get_input_ptr();
const outputPtr = lora.get_output_ptr();
const dim = lora.dim();
// Create views into WASM memory
const memory = new Float32Array(lora.memory.buffer);
const inputView = new Float32Array(memory.buffer, inputPtr, dim);
const outputView = new Float32Array(memory.buffer, outputPtr, dim);
// Write input directly
inputView.set(myInputData);
// Forward pass (zero allocation)
lora.forward();
// Read output directly
const result = outputView.slice();
// Adapt using input buffer as gradient
lora.adapt();
// Adapt with reward (for RL)
lora.adapt_with_reward(0.5); // improvement ratioPer-operator-type LoRA manager with 17 specialized adapters plus category fallback.
import init, { WasmScopedLoRA } from 'ruvector-learning-wasm';
await init();
const scopedLora = new WasmScopedLoRA(
256, // dim
0.1, // alpha
0.01 // learning_rate
);
// Operator types (0-16)
const HNSW_SCAN = 2;
const HASH_JOIN = 5;
const FILTER = 9;
// Forward for specific operator
const input = new Float32Array(256).fill(1.0);
const output = scopedLora.forward_array(HNSW_SCAN, input);
// Adapt for specific operator
const gradient = new Float32Array(256).fill(0.1);
scopedLora.adapt_array(FILTER, gradient);
// Per-operator statistics
console.log('HNSW forward count:', scopedLora.forward_count(HNSW_SCAN));
console.log('Filter adapt count:', scopedLora.adapt_count(FILTER));
console.log('Filter delta norm:', scopedLora.delta_norm(FILTER));
// Total statistics
console.log('Total forwards:', scopedLora.total_forward_count());
console.log('Total adapts:', scopedLora.total_adapt_count());
// Get operator name
console.log(WasmScopedLoRA.scope_name(HNSW_SCAN)); // "HnswScan"
// Enable/disable category fallback (default: enabled)
scopedLora.set_category_fallback(true);
// Reset specific operator or all
scopedLora.reset_scope(FILTER);
scopedLora.reset_all();| Value | Name | Category |
|---|---|---|
| 0 | SeqScan | Scan |
| 1 | IndexScan | Scan |
| 2 | HnswScan | Scan |
| 3 | IvfFlatScan | Scan |
| 4 | NestedLoopJoin | Join |
| 5 | HashJoin | Join |
| 6 | MergeJoin | Join |
| 7 | Aggregate | Aggregation |
| 8 | GroupBy | Aggregation |
| 9 | Filter | Transform |
| 10 | Project | Transform |
| 11 | Sort | Order |
| 12 | Limit | Order |
| 13 | VectorDistance | Vector |
| 14 | Rerank | Vector |
| 15 | Materialize | Utility |
| 16 | Result | Utility |
Trajectory recording for reinforcement learning and pattern analysis.
import init, { WasmTrajectoryBuffer } from 'ruvector-learning-wasm';
await init();
const buffer = new WasmTrajectoryBuffer(
1000, // capacity: max trajectories to store
256 // embedding_dim
);
// Record a trajectory
const embedding = new Float32Array(256).fill(1.0);
buffer.record(
embedding,
2, // op_type: HnswScan
0, // attention_type
100.0, // execution_ms
150.0 // baseline_ms (improvement = 150/100 - 1 = 0.5)
);
// Get statistics
console.log('Total count:', buffer.total_count());
console.log('Buffer length:', buffer.len());
console.log('Mean improvement:', buffer.mean_improvement());
console.log('Best improvement:', buffer.best_improvement());
console.log('Success rate:', buffer.success_rate());
console.log('Best attention type:', buffer.best_attention());
console.log('Variance:', buffer.variance());
// Filter by quality
console.log('High quality count:', buffer.high_quality_count(0.5));
// Filter by operator
console.log('HnswScan trajectories:', buffer.count_by_operator(2));
// Reset buffer
buffer.reset();Input Embedding (d-dim)
|
v
+---------+
| A: d x 2 | Down projection
+---------+
|
v
+---------+
| B: 2 x d | Up projection (initialized to zero)
+---------+
|
v
Delta W = alpha * (A @ B)
|
v
Output = Input + Delta W
When an operator has fewer than 10 adaptations, the output is blended with the category adapter based on relative experience:
weight = min(operator_adapt_count / 10, 1.0)
output = operator_output * weight + category_output * (1 - weight)
This enables transfer learning between similar operators (e.g., all scan types share Scan category knowledge).
- Forward pass: ~50us for 256-dim embeddings
- Adaptation: ~30us for gradient update
- Memory: ~2KB per LoRA pair (A + B matrices)
- WASM size: ~39KB (release build)
Full TypeScript definitions are included in the package:
export class WasmMicroLoRA {
constructor(dim?: number, alpha?: number, learning_rate?: number);
get_input_ptr(): number;
get_output_ptr(): number;
dim(): number;
forward(): void;
forward_array(input: Float32Array): Float32Array;
adapt(): void;
adapt_array(gradient: Float32Array): void;
adapt_with_reward(improvement: number): void;
reset(): void;
forward_count(): bigint;
adapt_count(): bigint;
delta_norm(): number;
param_count(): number;
}
export class WasmScopedLoRA {
constructor(dim?: number, alpha?: number, learning_rate?: number);
get_input_ptr(): number;
get_output_ptr(): number;
forward(op_type: number): void;
forward_array(op_type: number, input: Float32Array): Float32Array;
adapt(op_type: number): void;
adapt_array(op_type: number, gradient: Float32Array): void;
adapt_with_reward(op_type: number, improvement: number): void;
reset_scope(op_type: number): void;
reset_all(): void;
forward_count(op_type: number): bigint;
adapt_count(op_type: number): bigint;
delta_norm(op_type: number): number;
total_forward_count(): bigint;
total_adapt_count(): bigint;
set_category_fallback(enabled: boolean): void;
static scope_name(op_type: number): string;
}
export class WasmTrajectoryBuffer {
constructor(capacity?: number, embedding_dim?: number);
record(
embedding: Float32Array,
op_type: number,
attention_type: number,
execution_ms: number,
baseline_ms: number
): void;
total_count(): bigint;
len(): number;
is_empty(): boolean;
mean_improvement(): number;
best_improvement(): number;
success_rate(): number;
best_attention(): number;
variance(): number;
reset(): void;
high_quality_count(threshold: number): number;
count_by_operator(op_type: number): number;
}MIT OR Apache-2.0