Skip to content

Commit

Permalink
Merge pull request #64 from ashvardanian/main-dev
Browse files Browse the repository at this point in the history
Make: ESM and CommonJS release with fallbacks (#63)
  • Loading branch information
ashvardanian authored Jan 18, 2024
2 parents 549fd27 + d57f82b commit a6ca012
Show file tree
Hide file tree
Showing 20 changed files with 468 additions and 150 deletions.
1 change: 1 addition & 0 deletions .github/workflows/prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,5 @@ jobs:
run: |
npm ci --ignore-scripts
npm run install
npm run build-js
npm test
23 changes: 18 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ jobs:
- uses: actions/checkout@v3
with:
persist-credentials: false
- uses: actions/setup-node@v3
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- run: npm install --ignore-scripts --save-dev --prefix ./package-ci @semantic-release/exec @semantic-release/git conventional-changelog-eslint semantic-release && npx --prefix ./package-ci semantic-release

rebase:
name: Rebase Dev. Branch
if: github.ref_name == 'main'
if: github.ref == 'refs/heads/main'
needs: versioning
runs-on: ubuntu-22.04
steps:
Expand Down Expand Up @@ -83,6 +86,7 @@ jobs:

publish_python:
name: Publish Python
if: github.ref == 'refs/heads/main'
needs: build_wheels
runs-on: ubuntu-22.04
environment:
Expand All @@ -105,7 +109,7 @@ jobs:
print-hash: true

build_javascript:
name: Build JavaScript
name: Build JavaScript Native Modules
needs: versioning
strategy:
fail-fast: false
Expand Down Expand Up @@ -146,7 +150,7 @@ jobs:
sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
- run: npm ci --ignore-scripts
- run: npm run prebuild
- run: npm run prebuild-single
if: matrix.os != 'macos-latest'
- run: npm run prebuild-darwin-x64+arm64
env:
Expand Down Expand Up @@ -183,7 +187,16 @@ jobs:
- name: Look for links
run: find . -type f -links +1

- name: Test publish
- name: Install dependencies
run: npm ci --ignore-scripts

- name: Build the JS from TS
run: npm run build-js

- name: Last minute test with prebuild artifact
run: npm run test

- name: Publish Dry Run
run: npm publish --dry-run
if: github.ref != 'refs/heads/main'

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ node_modules/
package-ci/
prebuilds/
build/
javascript/dist

# for Google Benchmark
compare.py
Expand Down
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ VERSION
package-ci.json
setup.py
CMakeLists.txt
build
51 changes: 51 additions & 0 deletions bench.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const benchmark = require('benchmark');

// Assuming the vectors are of the same length
function cosineDistance(a, b) {
let dotProduct = 0;
let magA = 0;
let magB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
magA += a[i] * a[i];
magB += b[i] * b[i];
}
return 1 - (dotProduct / (Math.sqrt(magA) * Math.sqrt(magB)));
}


// Generate random data for testing
const dimensions = 1536; // Adjust dimensions as needed
const array1 = Array.from({ length: dimensions }, () => Math.random() * 100);
const array2 = Array.from({ length: dimensions }, () => Math.random() * 100);
const floatArray1 = new Float32Array(array1);
const floatArray2 = new Float32Array(array2);


// Create benchmark suite
const singleSuite = new benchmark.Suite('Single Vector Processing');

// Single-vector processing benchmarks
singleSuite

// Pure JavaScript
.add('Array of Numbers', () => {
cosineDistance(array1, array2);
})
.add('TypedArray of Float32', () => {
cosineDistance(floatArray1, floatArray2);
})
.on('cycle', (event) => {
if (event.target.error) {
console.error(String(event.target.error));
} else {
console.log(String(event.target));
}
})
.on('complete', () => {
console.log('Fastest Single-Vector Processing is ' + singleSuite.filter('fastest').map('name'));
})
.run({
noCache: true,
async: false,
});
4 changes: 2 additions & 2 deletions golang/simsimd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ inline static simsimd_f32_t sqeuclidean_f32(simsimd_f32_t const* a, simsimd_f32_
import "C"


// CosineI8 computes the cosine similarity between two i8 vectors using the most suitable SIMD instruction set available.
// CosineI8 computes the cosine distance between two i8 vectors using the most suitable SIMD instruction set available.
func CosineI8(a, b []int8) float32 {
return float32(C.cosine_i8((*C.simsimd_i8_t)(&a[0]), (*C.simsimd_i8_t)(&b[0]), C.simsimd_size_t(len(a))))
}

// CosineF32 computes the cosine similarity between two i8 vectors using the most suitable SIMD instruction set available.
// CosineF32 computes the cosine distance between two i8 vectors using the most suitable SIMD instruction set available.
func CosineF32(a, b []float32) float32 {
return float32(C.cosine_f32((*C.simsimd_f32_t)(&a[0]), (*C.simsimd_f32_t)(&b[0]), C.simsimd_size_t(len(a))))
}
Expand Down
12 changes: 5 additions & 7 deletions javascript/bench.mjs → javascript/bench.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import benchmark from 'benchmark';
import * as math from 'mathjs';
import usearch, { MetricKind } from 'usearch';
import build from 'node-gyp-build';
import process from 'node:process';

const simsimd = build(process.cwd());
const benchmark = require('benchmark');
const math = require('mathjs');
const usearch = require('usearch');
const MetricKind = usearch.MetricKind;
const simsimd = require("./dist/cjs/simsimd.js");

// Assuming the vectors are of the same length
function cosineDistance(a, b) {
Expand Down
3 changes: 3 additions & 0 deletions javascript/dist-package-cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
3 changes: 3 additions & 0 deletions javascript/dist-package-esm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
73 changes: 73 additions & 0 deletions javascript/fallback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
console.warn(
"It seems like your environment does't support the native simsimd module, so we are providing a JS fallback."
);

/**
* Computes the inner distance between two arrays.
* @param {number[]} arr1 - The first array.
* @param {number[]} arr2 - The second array.
* @returns {number} The inner distance between arr1 and arr2.
*/
export function inner_distance(arr1: number[], arr2: number[]): number {
if (arr1.length !== arr2.length) {
throw new Error("Vectors must have the same length");
}

let result = 0;
for (let i = 0; i < arr1.length; i++) {
result += arr1[i] * arr2[i];
}
return 1 - result;
}

/**
* Computes the squared Euclidean distance between two arrays.
* @param {number[]} arr1 - The first array.
* @param {number[]} arr2 - The second array.
* @returns {number} The squared Euclidean distance between arr1 and arr2.
*/
export function sqeuclidean(arr1: number[], arr2: number[]): number {
if (arr1.length !== arr2.length) {
throw new Error("Vectors must have the same length");
}

let result = 0;
for (let i = 0; i < arr1.length; i++) {
result += (arr1[i] - arr2[i]) * (arr1[i] - arr2[i]);
}
return result;
}

/**
* Computes the cosine distance between two arrays.
* @param {number[]} arr1 - The first array.
* @param {number[]} arr2 - The second array.
* @returns {number} The cosine distance between arr1 and arr2.
*/
export function cosine(arr1: number[], arr2: number[]): number {
if (arr1.length !== arr2.length) {
throw new Error("Vectors must have the same length");
}

let dotProduct = 0;
let magnitudeA = 0;
let magnitudeB = 0;

for (let i = 0; i < arr1.length; i++) {
dotProduct += arr1[i] * arr2[i];
magnitudeA += arr1[i] * arr1[i];
magnitudeB += arr2[i] * arr2[i];
}

magnitudeA = Math.sqrt(magnitudeA);
magnitudeB = Math.sqrt(magnitudeB);

if (magnitudeA === 0 || magnitudeB === 0) {
console.warn(
"Warning: One of the magnitudes is zero. Cosine similarity is undefined."
);
return 0;
}

return 1 - dotProduct / (magnitudeA * magnitudeB);
}
1 change: 1 addition & 0 deletions javascript/node-gyp-build.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "node-gyp-build";
35 changes: 0 additions & 35 deletions javascript/simsimd.d.ts

This file was deleted.

47 changes: 0 additions & 47 deletions javascript/simsimd.js

This file was deleted.

Loading

0 comments on commit a6ca012

Please sign in to comment.