133 lines
4.4 KiB
JavaScript
133 lines
4.4 KiB
JavaScript
// Example: Basic usage of Ruvector GNN Node.js bindings
|
|
|
|
const {
|
|
RuvectorLayer,
|
|
TensorCompress,
|
|
differentiableSearch,
|
|
hierarchicalForward,
|
|
getCompressionLevel,
|
|
init
|
|
} = require('../index.js');
|
|
|
|
console.log(init());
|
|
console.log('');
|
|
|
|
// ==================== Example 1: GNN Layer ====================
|
|
console.log('=== Example 1: GNN Layer ===');
|
|
|
|
const layer = new RuvectorLayer(4, 8, 2, 0.1);
|
|
console.log('Created GNN layer (input_dim: 4, hidden_dim: 8, heads: 2, dropout: 0.1)');
|
|
|
|
const nodeEmbedding = [1.0, 2.0, 3.0, 4.0];
|
|
const neighborEmbeddings = [
|
|
[0.5, 1.0, 1.5, 2.0],
|
|
[2.0, 3.0, 4.0, 5.0],
|
|
];
|
|
const edgeWeights = [0.3, 0.7];
|
|
|
|
const output = layer.forward(nodeEmbedding, neighborEmbeddings, edgeWeights);
|
|
console.log('Input embedding:', nodeEmbedding);
|
|
console.log('Output embedding (length):', output.length);
|
|
console.log('Output embedding (first 4 values):', output.slice(0, 4).map(x => x.toFixed(4)));
|
|
console.log('');
|
|
|
|
// ==================== Example 2: Tensor Compression ====================
|
|
console.log('=== Example 2: Tensor Compression ===');
|
|
|
|
const compressor = new TensorCompress();
|
|
const embedding = Array.from({ length: 64 }, (_, i) => Math.sin(i * 0.1));
|
|
|
|
// Test different access frequencies
|
|
const frequencies = [0.9, 0.5, 0.2, 0.05, 0.001];
|
|
|
|
frequencies.forEach(freq => {
|
|
const level = getCompressionLevel(freq);
|
|
const compressed = compressor.compress(embedding, freq);
|
|
const decompressed = compressor.decompress(compressed);
|
|
|
|
const originalSize = JSON.stringify(embedding).length;
|
|
const compressedSize = compressed.length;
|
|
const ratio = (compressedSize / originalSize * 100).toFixed(1);
|
|
|
|
console.log(`Frequency: ${freq.toFixed(3)} | Level: ${level.padEnd(6)} | Size: ${ratio}% | Error: ${calculateMSE(embedding, decompressed).toFixed(6)}`);
|
|
});
|
|
console.log('');
|
|
|
|
// ==================== Example 3: Differentiable Search ====================
|
|
console.log('=== Example 3: Differentiable Search ===');
|
|
|
|
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.7, 0.3, 0.0], // Medium match
|
|
[0.0, 1.0, 0.0], // Orthogonal
|
|
[0.0, 0.0, 1.0], // Orthogonal
|
|
];
|
|
|
|
console.log('Query:', query);
|
|
console.log('Number of candidates:', candidates.length);
|
|
|
|
const result = differentiableSearch(query, candidates, 3, 1.0);
|
|
console.log('Top-3 indices:', result.indices);
|
|
console.log('Soft weights:', result.weights.map(w => w.toFixed(4)));
|
|
console.log('Weights sum:', result.weights.reduce((a, b) => a + b, 0).toFixed(4));
|
|
console.log('');
|
|
|
|
// ==================== Example 4: Hierarchical Forward ====================
|
|
console.log('=== Example 4: Hierarchical Forward ===');
|
|
|
|
const query2 = [1.0, 0.0];
|
|
const layerEmbeddings = [
|
|
[
|
|
[1.0, 0.0],
|
|
[0.0, 1.0],
|
|
[0.7, 0.7],
|
|
],
|
|
];
|
|
|
|
const layer1 = new RuvectorLayer(2, 2, 1, 0.0);
|
|
const layers = [layer1.toJson()];
|
|
|
|
const finalEmbedding = hierarchicalForward(query2, layerEmbeddings, layers);
|
|
console.log('Query:', query2);
|
|
console.log('Final embedding:', finalEmbedding.map(x => x.toFixed(4)));
|
|
console.log('');
|
|
|
|
// ==================== Example 5: Layer Serialization ====================
|
|
console.log('=== Example 5: Layer Serialization ===');
|
|
|
|
const originalLayer = new RuvectorLayer(8, 16, 4, 0.2);
|
|
const serialized = originalLayer.toJson();
|
|
const deserialized = RuvectorLayer.fromJson(serialized);
|
|
|
|
console.log('Original layer created (8 -> 16, heads: 4, dropout: 0.2)');
|
|
console.log('Serialized size:', serialized.length, 'bytes');
|
|
console.log('Successfully deserialized');
|
|
|
|
// Test that deserialized layer works
|
|
const testInput = Array.from({ length: 8 }, () => Math.random());
|
|
const testNeighbors = [Array.from({ length: 8 }, () => Math.random())];
|
|
const testWeights = [1.0];
|
|
|
|
const output1 = originalLayer.forward(testInput, testNeighbors, testWeights);
|
|
const output2 = deserialized.forward(testInput, testNeighbors, testWeights);
|
|
|
|
console.log('Original output matches deserialized:', arraysEqual(output1, output2, 1e-6));
|
|
console.log('');
|
|
|
|
// ==================== Helper Functions ====================
|
|
|
|
function calculateMSE(a, b) {
|
|
if (a.length !== b.length) return Infinity;
|
|
const sum = a.reduce((acc, val, i) => acc + Math.pow(val - b[i], 2), 0);
|
|
return sum / a.length;
|
|
}
|
|
|
|
function arraysEqual(a, b, epsilon = 1e-10) {
|
|
if (a.length !== b.length) return false;
|
|
return a.every((val, i) => Math.abs(val - b[i]) < epsilon);
|
|
}
|
|
|
|
console.log('All examples completed successfully!');
|