npm package: @ruvector/gnn
Description: Graph Neural Network capabilities for Ruvector - Node.js bindings
Author: Ruvector Team
Latest version: 0.1.25

# @ruvector/gnn - Graph Neural Network Node.js Bindings

High-performance Graph Neural Network (GNN) capabilities for Ruvector, powered by Rust and NAPI-RS.

[![npm version](https://img.shields.io/npm/v/@ruvector/gnn.svg)](https://www.npmjs.com/package/@ruvector/gnn)
[![CI](https://github.com/ruvnet/ruvector/actions/workflows/build-gnn.yml/badge.svg)](https://github.com/ruvnet/ruvector/actions/workflows/build-gnn.yml)

## Features

- **GNN Layers**: Multi-head attention, layer normalization, GRU cells
- **Tensor Compression**: Adaptive compression with 5 levels (None, Half, PQ8, PQ4, Binary)
- **Differentiable Search**: Soft attention-based search with temperature scaling
- **Hierarchical Processing**: Multi-layer GNN forward pass
- **Zero-copy**: Efficient data transfer between JavaScript and Rust
- **TypeScript Support**: Full type definitions included

## Installation

```bash
npm install @ruvector/gnn
```

## Quick Start

### Creating a GNN Layer

```javascript
const { RuvectorLayer } = require('@ruvector/gnn');

// Create a GNN layer with:
// - Input dimension: 128
// - Hidden dimension: 256
// - Attention heads: 4
// - Dropout rate: 0.1
const layer = new RuvectorLayer(128, 256, 4, 0.1);

// Forward pass
const nodeEmbedding = new Array(128).fill(0).map(() => Math.random());
const neighborEmbeddings = [
  new Array(128).fill(0).map(() => Math.random()),
  new Array(128).fill(0).map(() => Math.random()),
];
const edgeWeights = [0.7, 0.3];

const output = layer.forward(nodeEmbedding, neighborEmbeddings, edgeWeights);
console.log('Output dimension:', output.length); // 256
```

### Tensor Compression

```javascript
const { TensorCompress, getCompressionLevel } = require('@ruvector/gnn');

const compressor = new TensorCompress();
const embedding = new Array(128).fill(0).map(() => Math.random());

// Adaptive compression based on access frequency
const accessFreq = 0.5; // 50% access rate
console.log('Selected level:', getCompressionLevel(accessFreq)); // "half"

const compressed = compressor.compress(embedding, accessFreq);
const decompressed = compressor.decompress(compressed);

console.log('Original size:', embedding.length);
console.log('Compression ratio:', compressed.length / JSON.stringify(embedding).length);

// Explicit compression level
const level = {
  level_type: 'pq8',
  subvectors: 8,
  centroids: 16
};
const compressedPQ = compressor.compressWithLevel(embedding, level);
```

### Differentiable Search

```javascript
const { differentiableSearch } = require('@ruvector/gnn');

const query = [1.0, 0.0, 0.0];
const candidates = [
  [1.0, 0.0, 0.0],  // Perfect match
  [0.9, 0.1, 0.0],  // Close match
  [0.0, 1.0, 0.0],  // Orthogonal
];

const result = differentiableSearch(query, candidates, 2, 1.0);
console.log('Top-2 indices:', result.indices);    // [0, 1]
console.log('Soft weights:', result.weights);     // [0.x, 0.y]
```

### Hierarchical Forward Pass

```javascript
const { hierarchicalForward, RuvectorLayer } = require('@ruvector/gnn');

const query = [1.0, 0.0];

// Layer embeddings (organized by HNSW layers)
const layerEmbeddings = [
  [[1.0, 0.0], [0.0, 1.0]],  // Layer 0 embeddings
];

// Create and serialize GNN layers
const layer1 = new RuvectorLayer(2, 2, 1, 0.0);
const layers = [layer1.toJson()];

// Hierarchical processing
const result = hierarchicalForward(query, layerEmbeddings, layers);
console.log('Final embedding:', result);
```

## API Reference

### RuvectorLayer

#### Constructor

```typescript
new RuvectorLayer(
  inputDim: number,
  hiddenDim: number,
  heads: number,
  dropout: number
): RuvectorLayer
```

#### Methods

- `forward(nodeEmbedding: number[], neighborEmbeddings: number[][], edgeWeights: number[]): number[]`
- `toJson(): string` - Serialize layer to JSON
- `fromJson(json: string): RuvectorLayer` - Deserialize layer from JSON

### TensorCompress

#### Constructor

```typescript
new TensorCompress(): TensorCompress
```

#### Methods

- `compress(embedding: number[], accessFreq: number): string` - Adaptive compression
- `compressWithLevel(embedding: number[], level: CompressionLevelConfig): string` - Explicit level
- `decompress(compressedJson: string): number[]` - Decompress tensor

#### CompressionLevelConfig

```typescript
interface CompressionLevelConfig {
  level_type: 'none' | 'half' | 'pq8' | 'pq4' | 'binary';
  scale?: number;           // For 'half'
  subvectors?: number;      // For 'pq8', 'pq4'
  centroids?: number;       // For 'pq8'
  outlier_threshold?: number; // For 'pq4'
  threshold?: number;       // For 'binary'
}
```

### Search Functions

#### differentiableSearch

```typescript
function differentiableSearch(
  query: number[],
  candidateEmbeddings: number[][],
  k: number,
  temperature: number
): { indices: number[], weights: number[] }
```

#### hierarchicalForward

```typescript
function hierarchicalForward(
  query: number[],
  layerEmbeddings: number[][][],
  gnnLayersJson: string[]
): number[]
```

### Utility Functions

#### getCompressionLevel

```typescript
function getCompressionLevel(accessFreq: number): string
```

Returns the compression level that would be selected for the given access frequency:
- `accessFreq > 0.8`: "none" (hot data)
- `accessFreq > 0.4`: "half" (warm data)
- `accessFreq > 0.1`: "pq8" (cool data)
- `accessFreq > 0.01`: "pq4" (cold data)
- `accessFreq <= 0.01`: "binary" (archive)

## Compression Levels

### None
Full precision, no compression. Best for frequently accessed data.

### Half Precision
~50% space savings with minimal quality loss. Good for warm data.

### PQ8 (8-bit Product Quantization)
~8x compression using 8-bit codes. Suitable for cool data.

### PQ4 (4-bit Product Quantization)
~16x compression with outlier handling. For cold data.

### Binary
~32x compression, values become +1/-1. For archival data.

## Performance

- **Zero-copy operations** where possible
- **SIMD optimizations** for vector operations
- **Parallel processing** with Rayon
- **Native performance** with Rust backend

## Building from Source

```bash
# Install dependencies
npm install

# Build debug
npm run build:debug

# Build release
npm run build

# Run tests
npm test
```

## License

MIT - See LICENSE file for details

## Contributing

Contributions are welcome! Please see the main Ruvector repository for guidelines.

## Links

- [GitHub Repository](https://github.com/ruvnet/ruvector)
- [Documentation](https://docs.ruvector.io)
- [Issues](https://github.com/ruvnet/ruvector/issues)