tasq/node_modules/@ruvector/gnn/index.js

508 lines
16 KiB
JavaScript

/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
const { existsSync, readFileSync } = require('fs')
const { join } = require('path')
const { platform, arch } = process
let nativeBinding = null
let localFileExisted = false
let loadError = null
function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
const lddPath = require('child_process').execSync('which ldd').toString().trim()
return readFileSync(lddPath, 'utf8').includes('musl')
} catch (e) {
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}
switch (platform) {
case 'android':
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'ruvector-gnn.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.android-arm64.node')
} else {
nativeBinding = require('@ruvector/gnn-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'ruvector-gnn.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.android-arm-eabi.node')
} else {
nativeBinding = require('@ruvector/gnn-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
break
case 'win32':
switch (arch) {
case 'x64':
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.win32-x64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.win32-x64-msvc.node')
} else {
nativeBinding = require('@ruvector/gnn-win32-x64-msvc')
}
} catch (e) {
loadError = e
}
break
case 'ia32':
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.win32-ia32-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.win32-ia32-msvc.node')
} else {
nativeBinding = require('@ruvector/gnn-win32-ia32-msvc')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.win32-arm64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.win32-arm64-msvc.node')
} else {
nativeBinding = require('@ruvector/gnn-win32-arm64-msvc')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
localFileExisted = existsSync(join(__dirname, 'ruvector-gnn.darwin-universal.node'))
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.darwin-universal.node')
} else {
nativeBinding = require('@ruvector/gnn-darwin-universal')
}
break
} catch {}
switch (arch) {
case 'x64':
localFileExisted = existsSync(join(__dirname, 'ruvector-gnn.darwin-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.darwin-x64.node')
} else {
nativeBinding = require('@ruvector/gnn-darwin-x64')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.darwin-arm64.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.darwin-arm64.node')
} else {
nativeBinding = require('@ruvector/gnn-darwin-arm64')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
case 'freebsd':
if (arch !== 'x64') {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
}
localFileExisted = existsSync(join(__dirname, 'ruvector-gnn.freebsd-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.freebsd-x64.node')
} else {
nativeBinding = require('@ruvector/gnn-freebsd-x64')
}
} catch (e) {
loadError = e
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-x64-musl.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-x64-gnu.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-x64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-arm64-musl.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-arm64-gnu.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-arm64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-arm-musleabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-arm-musleabihf.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-arm-musleabihf')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-arm-gnueabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
}
}
break
case 'riscv64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-riscv64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-riscv64-musl.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-riscv64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-riscv64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-riscv64-gnu.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-riscv64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 's390x':
localFileExisted = existsSync(
join(__dirname, 'ruvector-gnn.linux-s390x-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./ruvector-gnn.linux-s390x-gnu.node')
} else {
nativeBinding = require('@ruvector/gnn-linux-s390x-gnu')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}
if (!nativeBinding) {
if (loadError) {
throw loadError
}
throw new Error(`Failed to load native binding`)
}
const { RuvectorLayer: NativeRuvectorLayer, TensorCompress: NativeTensorCompress, differentiableSearch: nativeDifferentiableSearch, hierarchicalForward: nativeHierarchicalForward, getCompressionLevel, init } = nativeBinding
// ============================================================================
// Optimized Type Conversion Helpers
// The native Rust code expects Float32Array for maximum performance.
// These helpers convert any array-like input to Float32Array efficiently.
// ============================================================================
/**
* Convert any array-like to Float32Array (native Rust expects Float32Array)
* Optimized paths:
* - Float32Array: zero-copy return
* - Float64Array: efficient typed array copy
* - Array: direct Float32Array construction
* @param {number[] | Float32Array | Float64Array} input
* @returns {Float32Array}
*/
function toFloat32Array(input) {
// Fast path: already Float32Array - zero copy
if (input instanceof Float32Array) return input
// Float64Array: efficient typed array conversion
if (input instanceof Float64Array) return new Float32Array(input)
// Regular array: direct construction
if (Array.isArray(input)) return new Float32Array(input)
// Fallback for other array-likes
return new Float32Array(Array.from(input))
}
/**
* Convert array of arrays to array of Float32Arrays
* @param {(number[] | Float32Array | Float64Array)[]} input
* @returns {Float32Array[]}
*/
function toFloat32ArrayBatch(input) {
const result = new Array(input.length)
for (let i = 0; i < input.length; i++) {
result[i] = toFloat32Array(input[i])
}
return result
}
/**
* Batch convert with pre-allocated buffer for maximum performance
* Use when all vectors have the same dimension
* @param {(number[] | Float32Array | Float64Array)[]} input
* @param {number} dim - Vector dimension
* @returns {Float32Array[]}
*/
function toFloat32ArrayBatchOptimized(input, dim) {
const count = input.length
const result = new Array(count)
for (let i = 0; i < count; i++) {
const arr = input[i]
if (arr instanceof Float32Array) {
result[i] = arr
} else if (arr instanceof Float64Array) {
result[i] = new Float32Array(arr)
} else {
result[i] = new Float32Array(arr)
}
}
return result
}
// ============================================================================
// Wrapper Functions - Accept any array type, convert to Float32Array
// ============================================================================
/**
* Differentiable search using soft attention mechanism
* Accepts regular arrays or typed arrays, converts to Float32Array internally
* @param {number[] | Float32Array} query - Query vector
* @param {(number[] | Float32Array)[]} candidateEmbeddings - Candidate vectors
* @param {number} k - Number of results
* @param {number} temperature - Softmax temperature
* @returns {{indices: number[], weights: number[]}}
*/
function differentiableSearch(query, candidateEmbeddings, k, temperature) {
return nativeDifferentiableSearch(
toFloat32Array(query),
toFloat32ArrayBatch(candidateEmbeddings),
k,
temperature
)
}
/**
* Hierarchical forward pass through GNN layers
* @param {number[] | Float32Array} query - Query vector
* @param {(number[] | Float32Array)[][]} layerEmbeddings - Embeddings by layer
* @param {string[]} gnnLayersJson - Serialized GNN layers
* @returns {Float32Array}
*/
function hierarchicalForward(query, layerEmbeddings, gnnLayersJson) {
return nativeHierarchicalForward(
toFloat32Array(query),
layerEmbeddings.map(layer => toFloat32ArrayBatch(layer)),
gnnLayersJson
)
}
// ============================================================================
// Wrapped Classes
// ============================================================================
/**
* Graph Neural Network layer for HNSW topology
*/
class RuvectorLayer {
constructor(inputDim, hiddenDim, heads, dropout) {
this._native = new NativeRuvectorLayer(inputDim, hiddenDim, heads, dropout)
}
/**
* Forward pass through the GNN layer
* @param {number[] | Float32Array} nodeEmbedding - Node embedding
* @param {(number[] | Float32Array)[]} neighborEmbeddings - Neighbor embeddings
* @param {number[] | Float32Array} edgeWeights - Edge weights
* @returns {Float32Array}
*/
forward(nodeEmbedding, neighborEmbeddings, edgeWeights) {
return this._native.forward(
toFloat32Array(nodeEmbedding),
toFloat32ArrayBatch(neighborEmbeddings),
toFloat32Array(edgeWeights)
)
}
toJson() {
return this._native.toJson()
}
static fromJson(json) {
const layer = Object.create(RuvectorLayer.prototype)
layer._native = NativeRuvectorLayer.fromJson(json)
return layer
}
}
/**
* Tensor compressor with adaptive level selection
*/
class TensorCompress {
constructor() {
this._native = new NativeTensorCompress()
}
/**
* Compress embedding based on access frequency
* @param {number[] | Float32Array} embedding - Input embedding
* @param {number} accessFreq - Access frequency (0.0 - 1.0)
* @returns {string} Compressed JSON
*/
compress(embedding, accessFreq) {
return this._native.compress(toFloat32Array(embedding), accessFreq)
}
/**
* Compress with explicit compression level
* @param {number[] | Float32Array} embedding - Input embedding
* @param {object} level - Compression level config
* @returns {string} Compressed JSON
*/
compressWithLevel(embedding, level) {
return this._native.compressWithLevel(toFloat32Array(embedding), level)
}
/**
* Decompress a compressed tensor
* @param {string} compressedJson - Compressed JSON
* @returns {Float32Array}
*/
decompress(compressedJson) {
return this._native.decompress(compressedJson)
}
}
module.exports.RuvectorLayer = RuvectorLayer
module.exports.TensorCompress = TensorCompress
module.exports.differentiableSearch = differentiableSearch
module.exports.hierarchicalForward = hierarchicalForward
module.exports.getCompressionLevel = getCompressionLevel
module.exports.init = init
// Export conversion helpers for users who want to pre-convert their data
module.exports.toFloat32Array = toFloat32Array
module.exports.toFloat32ArrayBatch = toFloat32ArrayBatch
module.exports.toFloat32ArrayBatchOptimized = toFloat32ArrayBatchOptimized
// Also export native versions for advanced users (require Float32Array directly)
module.exports.NativeRuvectorLayer = NativeRuvectorLayer
module.exports.NativeTensorCompress = NativeTensorCompress
module.exports.nativeDifferentiableSearch = nativeDifferentiableSearch
module.exports.nativeHierarchicalForward = nativeHierarchicalForward