"use strict"; /** * GNN Wrapper - Safe wrapper around @ruvector/gnn with automatic array conversion * * This wrapper handles the array type conversion automatically, allowing users * to pass either regular arrays or Float32Arrays. * * The native @ruvector/gnn requires Float32Array for maximum performance. * This wrapper converts any input type to Float32Array automatically. * * Performance Tips: * - Pass Float32Array directly for zero-copy performance * - Use toFloat32Array/toFloat32ArrayBatch for pre-conversion * - Avoid repeated conversions in hot paths */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TensorCompress = exports.RuvectorLayer = void 0; exports.toFloat32Array = toFloat32Array; exports.toFloat32ArrayBatch = toFloat32ArrayBatch; exports.differentiableSearch = differentiableSearch; exports.hierarchicalForward = hierarchicalForward; exports.getCompressionLevel = getCompressionLevel; exports.isGnnAvailable = isGnnAvailable; // Lazy load to avoid import errors if not installed let gnnModule = null; let loadError = null; function getGnnModule() { if (gnnModule) return gnnModule; if (loadError) throw loadError; try { gnnModule = require('@ruvector/gnn'); return gnnModule; } catch (e) { loadError = new Error(`@ruvector/gnn is not installed or failed to load: ${e.message}\n` + `Install with: npm install @ruvector/gnn`); throw loadError; } } /** * Convert any array-like input to Float32Array (native requires Float32Array) * Optimized paths: * - Float32Array: zero-copy return * - Float64Array: efficient typed array copy * - Array: direct Float32Array construction */ function toFloat32Array(input) { if (input instanceof Float32Array) return input; if (input instanceof Float64Array) return new Float32Array(input); if (Array.isArray(input)) return new Float32Array(input); return new Float32Array(Array.from(input)); } /** * Convert array of arrays to array of Float32Arrays */ function toFloat32ArrayBatch(input) { const result = new Array(input.length); for (let i = 0; i < input.length; i++) { result[i] = toFloat32Array(input[i]); } return result; } /** * Differentiable search using soft attention mechanism * * This wrapper automatically converts Float32Array inputs to regular arrays. * * @param query - Query vector (array or Float32Array) * @param candidates - List of candidate vectors (arrays or Float32Arrays) * @param k - Number of top results to return * @param temperature - Temperature for softmax (lower = sharper, higher = smoother) * @returns Search result with indices and soft weights * * @example * ```typescript * import { differentiableSearch } from 'ruvector/core/gnn-wrapper'; * * // Works with regular arrays (auto-converted to Float32Array) * const result1 = differentiableSearch([1, 0, 0], [[1, 0, 0], [0, 1, 0]], 2, 1.0); * * // For best performance, use Float32Array directly (zero-copy) * const query = new Float32Array([1, 0, 0]); * const candidates = [new Float32Array([1, 0, 0]), new Float32Array([0, 1, 0])]; * const result2 = differentiableSearch(query, candidates, 2, 1.0); * ``` */ function differentiableSearch(query, candidates, k, temperature = 1.0) { const gnn = getGnnModule(); // Convert to Float32Array (native Rust expects Float32Array for performance) const queryFloat32 = toFloat32Array(query); const candidatesFloat32 = toFloat32ArrayBatch(candidates); return gnn.differentiableSearch(queryFloat32, candidatesFloat32, k, temperature); } /** * GNN Layer for HNSW topology */ class RuvectorLayer { /** * Create a new Ruvector GNN layer * * @param inputDim - Dimension of input node embeddings * @param hiddenDim - Dimension of hidden representations * @param heads - Number of attention heads * @param dropout - Dropout rate (0.0 to 1.0) */ constructor(inputDim, hiddenDim, heads, dropout = 0.1) { const gnn = getGnnModule(); this.inner = new gnn.RuvectorLayer(inputDim, hiddenDim, heads, dropout); } /** * Forward pass through the GNN layer * * @param nodeEmbedding - Current node's embedding * @param neighborEmbeddings - Embeddings of neighbor nodes * @param edgeWeights - Weights of edges to neighbors * @returns Updated node embedding as Float32Array */ forward(nodeEmbedding, neighborEmbeddings, edgeWeights) { return this.inner.forward(toFloat32Array(nodeEmbedding), toFloat32ArrayBatch(neighborEmbeddings), toFloat32Array(edgeWeights)); } /** * Serialize the layer to JSON */ toJson() { return this.inner.toJson(); } /** * Deserialize the layer from JSON */ static fromJson(json) { const gnn = getGnnModule(); const layer = new RuvectorLayer(1, 1, 1, 0); // Dummy constructor layer.inner = gnn.RuvectorLayer.fromJson(json); return layer; } } exports.RuvectorLayer = RuvectorLayer; /** * Tensor compressor with adaptive level selection */ class TensorCompress { constructor() { const gnn = getGnnModule(); this.inner = new gnn.TensorCompress(); } /** * Compress an embedding based on access frequency * * @param embedding - Input embedding vector * @param accessFreq - Access frequency (0.0 to 1.0) * @returns Compressed tensor as JSON string */ compress(embedding, accessFreq) { return this.inner.compress(toFloat32Array(embedding), accessFreq); } /** * Decompress a compressed tensor * * @param compressedJson - Compressed tensor JSON * @returns Decompressed embedding */ decompress(compressedJson) { return this.inner.decompress(compressedJson); } } exports.TensorCompress = TensorCompress; /** * Hierarchical forward pass through GNN layers * * @param query - Query vector * @param layerEmbeddings - Embeddings organized by layer * @param gnnLayersJson - JSON array of serialized GNN layers * @returns Final embedding after hierarchical processing as Float32Array */ function hierarchicalForward(query, layerEmbeddings, gnnLayersJson) { const gnn = getGnnModule(); return gnn.hierarchicalForward(toFloat32Array(query), layerEmbeddings.map(layer => toFloat32ArrayBatch(layer)), gnnLayersJson); } /** * Get compression level for a given access frequency */ function getCompressionLevel(accessFreq) { const gnn = getGnnModule(); return gnn.getCompressionLevel(accessFreq); } /** * Check if GNN module is available */ function isGnnAvailable() { try { getGnnModule(); return true; } catch { return false; } } exports.default = { differentiableSearch, RuvectorLayer, TensorCompress, hierarchicalForward, getCompressionLevel, isGnnAvailable, // Export conversion helpers for performance optimization toFloat32Array, toFloat32ArrayBatch, };