usearch 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +9 -0
- package/CMakeListsInstructuons.md +29 -3
- package/Cargo.toml +3 -3
- package/VERSION +1 -1
- package/binding.gyp +2 -1
- package/build.gradle +111 -0
- package/build.rs +6 -5
- package/java/cloud/unum/usearch/Index.java +161 -0
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +173 -0
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.h +109 -0
- package/java/test/IndexTest.java +26 -0
- package/package.json +2 -2
- package/pom.xml +8 -0
- package/{src/python.cpp → python/lib.cpp} +2 -24
- package/{src/rust.cpp → rust/lib.cpp} +3 -3
- package/{src → rust}/lib.rs +1 -1
- package/setup.py +2 -2
- package/src/advanced.hpp +24 -7
- package/wolfram/lib.cpp +21 -0
- /package/{src/javascript.cpp → javascript/lib.cpp} +0 -0
- /package/{src → javascript}/test.js +0 -0
- /package/{src → python}/bench.py +0 -0
- /package/{src → python}/test.py +0 -0
- /package/{src/rust.hpp → rust/lib.hpp} +0 -0
package/.gitattributes
ADDED
|
@@ -47,10 +47,10 @@ cmake \
|
|
|
47
47
|
|
|
48
48
|
```sh
|
|
49
49
|
pip install -e .
|
|
50
|
-
python
|
|
50
|
+
python python/test.py
|
|
51
51
|
|
|
52
52
|
# To benchmark:
|
|
53
|
-
python
|
|
53
|
+
python python/bench.py \
|
|
54
54
|
--vectors datasets/wiki_1M/base.1M.fbin \
|
|
55
55
|
--queries datasets/wiki_1M/query.public.100K.fbin \
|
|
56
56
|
--neighbors datasets/wiki_1M/groundtruth.public.100K.ibin \
|
|
@@ -61,7 +61,7 @@ python src/bench.py \
|
|
|
61
61
|
|
|
62
62
|
```sh
|
|
63
63
|
npm install
|
|
64
|
-
node
|
|
64
|
+
node javascript/test.js
|
|
65
65
|
npm publish
|
|
66
66
|
```
|
|
67
67
|
|
|
@@ -74,8 +74,34 @@ cargo publish
|
|
|
74
74
|
|
|
75
75
|
### Java
|
|
76
76
|
|
|
77
|
+
```sh
|
|
78
|
+
cs java/unum/cloud/usearch
|
|
79
|
+
javac -h . Index.java
|
|
80
|
+
|
|
81
|
+
# Ubuntu:
|
|
82
|
+
g++ -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
|
|
83
|
+
g++ -shared -fPIC -o libUSearchJNI.so cloud_unum_usearch_Index.o -lc
|
|
84
|
+
|
|
85
|
+
# Windows
|
|
86
|
+
g++ -c -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
|
|
87
|
+
g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
|
|
88
|
+
|
|
89
|
+
# MacOS
|
|
90
|
+
g++ -std=c++11 -c -fPIC \
|
|
91
|
+
-I../../../../include -I../../../../src -I../../../../fp16/include -I../../../../simsimd/include \
|
|
92
|
+
-I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
|
|
93
|
+
g++ -dynamiclib -o libUSearchJNI.dylib cloud_unum_usearch_Index.o -lc
|
|
94
|
+
# Run linking to that directory
|
|
95
|
+
java -cp . -Djava.library.path=/Users/av/github/usearch/java/cloud/unum/usearch/ Index.java
|
|
96
|
+
java -cp . -Djava.library.path=/Users/av/github/usearch/java cloud.unum.usearch.Index
|
|
97
|
+
```
|
|
98
|
+
|
|
77
99
|
### Wolfram
|
|
78
100
|
|
|
101
|
+
```sh
|
|
102
|
+
brew install --cask wolfram-engine
|
|
103
|
+
```
|
|
104
|
+
|
|
79
105
|
## Benchmarks
|
|
80
106
|
|
|
81
107
|
### Datasets
|
package/Cargo.toml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "usearch"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.6"
|
|
4
4
|
authors = ["Ashot Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
|
|
5
|
-
description = "The Tiny Vector Search Engine
|
|
5
|
+
description = "The Mighty Tiny Vector Search Engine with Automatic Quantization and Hardware Acceleration"
|
|
6
6
|
edition = "2021"
|
|
7
7
|
license = "Apache-2.0"
|
|
8
8
|
publish = true
|
|
@@ -10,7 +10,7 @@ repository = "https://github.com/unum-cloud/usearch"
|
|
|
10
10
|
|
|
11
11
|
[lib]
|
|
12
12
|
name = "usearch"
|
|
13
|
-
path = "
|
|
13
|
+
path = "rust/lib.rs"
|
|
14
14
|
|
|
15
15
|
[dependencies]
|
|
16
16
|
cxx = "1.0"
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.6
|
package/binding.gyp
CHANGED
package/build.gradle
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import org.gradle.internal.jvm.Jvm
|
|
2
|
+
|
|
3
|
+
plugins {
|
|
4
|
+
id 'java-library'
|
|
5
|
+
id 'c'
|
|
6
|
+
id 'cpp'
|
|
7
|
+
id 'maven-publish'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
group "cloud.unum.usearch"
|
|
11
|
+
version = file("VERSION").text.trim()
|
|
12
|
+
|
|
13
|
+
sourceCompatibility = 1.8
|
|
14
|
+
targetCompatibility = 1.8
|
|
15
|
+
|
|
16
|
+
repositories {
|
|
17
|
+
mavenCentral()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
sourceSets {
|
|
21
|
+
main {
|
|
22
|
+
java {
|
|
23
|
+
srcDir "java/"
|
|
24
|
+
exclude "java/test/"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
test {
|
|
28
|
+
java {
|
|
29
|
+
srcDir "java/test"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
dependencies {
|
|
35
|
+
testImplementation('junit:junit:4.13.2')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
model {
|
|
39
|
+
|
|
40
|
+
components {
|
|
41
|
+
usearch(NativeLibrarySpec) {
|
|
42
|
+
sources {
|
|
43
|
+
cpp {
|
|
44
|
+
source {
|
|
45
|
+
srcDirs "cloud/unum/usearch"
|
|
46
|
+
include "**/*.cpp"
|
|
47
|
+
}
|
|
48
|
+
exportedHeaders {
|
|
49
|
+
srcDirs "include", "src", "${Jvm.current().javaHome}/include"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
binaries.withType(StaticLibraryBinarySpec) {
|
|
54
|
+
buildable = false
|
|
55
|
+
}
|
|
56
|
+
binaries.withType(SharedLibraryBinarySpec) {
|
|
57
|
+
if (targetPlatform.operatingSystem.linux) {
|
|
58
|
+
cppCompiler.args '-I', "${Jvm.current().javaHome}/include/linux"
|
|
59
|
+
cppCompiler.args '-D_FILE_OFFSET_BITS=64'
|
|
60
|
+
} else if (targetPlatform.operatingSystem.macOsX) {
|
|
61
|
+
cppCompiler.args '-I', "${Jvm.current().javaHome}/include/darwin"
|
|
62
|
+
cppCompiler.args '-D_FILE_OFFSET_BITS=64'
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
test {
|
|
70
|
+
forkEvery 1
|
|
71
|
+
|
|
72
|
+
dependsOn jar
|
|
73
|
+
|
|
74
|
+
// Rearrange test classpath, add compiled JAR instead of main classes
|
|
75
|
+
classpath = project.sourceSets.test.output + configurations.testRuntimeClasspath + files(jar.archiveFile)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
jar {
|
|
79
|
+
dependsOn("usearchSharedLibrary")
|
|
80
|
+
from("$buildDir/libs/usearch/shared/libUSearchJNI.dylib")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
publishing {
|
|
84
|
+
publications {
|
|
85
|
+
library(MavenPublication) {
|
|
86
|
+
from components.java
|
|
87
|
+
|
|
88
|
+
pom {
|
|
89
|
+
name = "USearch"
|
|
90
|
+
description = "The Mighty Tiny Vector Search Engine with Automatic Quantization and Hardware Acceleration"
|
|
91
|
+
url = "https://github.com/unum-cloud/usearch"
|
|
92
|
+
licenses {
|
|
93
|
+
license {
|
|
94
|
+
name = 'The Apache License, Version 2.0'
|
|
95
|
+
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
repositories {
|
|
102
|
+
maven {
|
|
103
|
+
name = "OSSRH"
|
|
104
|
+
url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
|
105
|
+
credentials {
|
|
106
|
+
username = System.getenv("MAVEN_USERNAME")
|
|
107
|
+
password = System.getenv("MAVEN_PASSWORD")
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
package/build.rs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
fn main() {
|
|
2
|
-
cxx_build::bridge("
|
|
3
|
-
.file("
|
|
2
|
+
cxx_build::bridge("rust/lib.rs")
|
|
3
|
+
.file("rust/lib.cpp")
|
|
4
4
|
.flag_if_supported("-std=c++11")
|
|
5
5
|
.include("include")
|
|
6
|
+
.include("rust")
|
|
6
7
|
.include("src")
|
|
7
8
|
.include("fp16/include")
|
|
8
9
|
.include("simsimd/include")
|
|
9
10
|
.compile("usearch");
|
|
10
11
|
|
|
11
|
-
println!("cargo:rerun-if-changed=
|
|
12
|
-
println!("cargo:rerun-if-changed=
|
|
13
|
-
println!("cargo:rerun-if-changed=
|
|
12
|
+
println!("cargo:rerun-if-changed=rust/lib.rs");
|
|
13
|
+
println!("cargo:rerun-if-changed=rust/lib.cpp");
|
|
14
|
+
println!("cargo:rerun-if-changed=rust/lib.hpp");
|
|
14
15
|
println!("cargo:rerun-if-changed=src/advanced.hpp");
|
|
15
16
|
println!("cargo:rerun-if-changed=include/usearch/usearch.hpp");
|
|
16
17
|
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
package cloud.unum.usearch;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @brief Java bindings for Unum USearch.
|
|
5
|
+
*
|
|
6
|
+
* @see Tutorials:
|
|
7
|
+
* https://nachtimwald.com/2017/06/06/wrapping-a-c-library-in-java/
|
|
8
|
+
* https://www3.ntu.edu.sg/home/ehchua/programming/java/javanativeinterface.html
|
|
9
|
+
*/
|
|
10
|
+
public class Index {
|
|
11
|
+
|
|
12
|
+
private long c_ptr = 0;
|
|
13
|
+
|
|
14
|
+
public Index(String metric, String accuracy, //
|
|
15
|
+
long dimensions, long capacity, long connectivity, //
|
|
16
|
+
long expansion_add, long expansion_search) {
|
|
17
|
+
c_ptr = c_create(
|
|
18
|
+
metric,
|
|
19
|
+
accuracy,
|
|
20
|
+
dimensions,
|
|
21
|
+
capacity,
|
|
22
|
+
connectivity,
|
|
23
|
+
expansion_add,
|
|
24
|
+
expansion_search);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public long size() {
|
|
28
|
+
return c_size(c_ptr);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public long connectivity() {
|
|
32
|
+
return c_connectivity(c_ptr);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public long dimensions() {
|
|
36
|
+
return c_dimensions(c_ptr);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public long capacity() {
|
|
40
|
+
return c_capacity(c_ptr);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public void reserve(long capacity) {
|
|
44
|
+
c_reserve(c_ptr, capacity);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public void add(int label, float vector[]) {
|
|
48
|
+
c_add(c_ptr, label, vector);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public int[] search(float vector[], long count) {
|
|
52
|
+
return c_search(c_ptr, vector, count);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public void save(String path) {
|
|
56
|
+
c_save(c_ptr, path);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public void load(String path) {
|
|
60
|
+
c_load(c_ptr, path);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public void view(String path) {
|
|
64
|
+
c_view(c_ptr, path);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public static class Config {
|
|
68
|
+
private String _metric = "ip";
|
|
69
|
+
private String _accuracy = "f32";
|
|
70
|
+
private long _dimensions = 0;
|
|
71
|
+
private long _capacity = 0;
|
|
72
|
+
private long _connectivity = 0;
|
|
73
|
+
private long _expansion_add = 0;
|
|
74
|
+
private long _expansion_search = 0;
|
|
75
|
+
|
|
76
|
+
public Config() {
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public Index build() {
|
|
80
|
+
return new Index(
|
|
81
|
+
_metric,
|
|
82
|
+
_accuracy,
|
|
83
|
+
_dimensions,
|
|
84
|
+
_capacity,
|
|
85
|
+
_connectivity,
|
|
86
|
+
_expansion_add,
|
|
87
|
+
_expansion_search);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public Config metric(String _metric) {
|
|
91
|
+
this._metric = _metric;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public Config accuracy(String _accuracy) {
|
|
96
|
+
this._accuracy = _accuracy;
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public Config dimensions(long _dimensions) {
|
|
101
|
+
this._dimensions = _dimensions;
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public Config capacity(long _capacity) {
|
|
106
|
+
this._capacity = _capacity;
|
|
107
|
+
return this;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public Config connectivity(long _connectivity) {
|
|
111
|
+
this._connectivity = _connectivity;
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public Config expansion_add(long _expansion_add) {
|
|
116
|
+
this._expansion_add = _expansion_add;
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public Config expansion_search(long _expansion_search) {
|
|
121
|
+
this._expansion_search = _expansion_search;
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static {
|
|
127
|
+
System.loadLibrary("USearchJNI");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public static void main(String[] args) {
|
|
131
|
+
Index index = new Index.Config().metric("cos").build();
|
|
132
|
+
index.size();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private static native long c_create(//
|
|
136
|
+
String metric, String accuracy, //
|
|
137
|
+
long dimensions, long capacity, long connectivity, //
|
|
138
|
+
long expansion_add, long expansion_search);
|
|
139
|
+
|
|
140
|
+
private static native void c_destroy(long ptr);
|
|
141
|
+
|
|
142
|
+
private static native long c_size(long ptr);
|
|
143
|
+
|
|
144
|
+
private static native long c_connectivity(long ptr);
|
|
145
|
+
|
|
146
|
+
private static native long c_dimensions(long ptr);
|
|
147
|
+
|
|
148
|
+
private static native long c_capacity(long ptr);
|
|
149
|
+
|
|
150
|
+
private static native void c_reserve(long ptr, long capacity);
|
|
151
|
+
|
|
152
|
+
private static native void c_add(long ptr, int label, float vector[]);
|
|
153
|
+
|
|
154
|
+
private static native int[] c_search(long ptr, float vector[], long count);
|
|
155
|
+
|
|
156
|
+
private static native void c_save(long ptr, String path);
|
|
157
|
+
|
|
158
|
+
private static native void c_load(long ptr, String path);
|
|
159
|
+
|
|
160
|
+
private static native void c_view(long ptr, String path);
|
|
161
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#include <jni.h>
|
|
2
|
+
|
|
3
|
+
#include "cloud_unum_usearch_Index.h"
|
|
4
|
+
|
|
5
|
+
#include <thread>
|
|
6
|
+
|
|
7
|
+
#include "advanced.hpp"
|
|
8
|
+
|
|
9
|
+
using namespace unum::usearch;
|
|
10
|
+
using namespace unum;
|
|
11
|
+
|
|
12
|
+
using label_t = jint;
|
|
13
|
+
using distance_t = punned_distance_t;
|
|
14
|
+
using native_index_t = auto_index_gt<label_t>;
|
|
15
|
+
using span_t = span_gt<float>;
|
|
16
|
+
|
|
17
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create( //
|
|
18
|
+
JNIEnv* env, jclass, //
|
|
19
|
+
jstring metric, jstring accuracy, //
|
|
20
|
+
jlong dimensions, jlong capacity, jlong connectivity, //
|
|
21
|
+
jlong expansion_add, jlong expansion_search) {
|
|
22
|
+
|
|
23
|
+
jlong result{};
|
|
24
|
+
char const* metric_cstr{};
|
|
25
|
+
char const* accuracy_cstr{};
|
|
26
|
+
try {
|
|
27
|
+
|
|
28
|
+
config_t config;
|
|
29
|
+
config.expansion_add = static_cast<std::size_t>(expansion_add);
|
|
30
|
+
config.expansion_search = static_cast<std::size_t>(expansion_search);
|
|
31
|
+
config.connectivity = static_cast<std::size_t>(connectivity);
|
|
32
|
+
config.max_elements = static_cast<std::size_t>(capacity);
|
|
33
|
+
config.max_threads_add = std::thread::hardware_concurrency();
|
|
34
|
+
config.max_threads_search = std::thread::hardware_concurrency();
|
|
35
|
+
|
|
36
|
+
metric_cstr = (*env).GetStringUTFChars(metric, 0);
|
|
37
|
+
std::size_t metric_length = (*env).GetStringUTFLength(metric);
|
|
38
|
+
accuracy_cstr = (*env).GetStringUTFChars(accuracy, 0);
|
|
39
|
+
std::size_t accuracy_length = (*env).GetStringUTFLength(accuracy);
|
|
40
|
+
|
|
41
|
+
accuracy_t accuracy = accuracy_from_name(accuracy_cstr, accuracy_length);
|
|
42
|
+
native_index_t index = index_from_name<native_index_t>( //
|
|
43
|
+
metric_cstr, metric_length, static_cast<std::size_t>(dimensions), accuracy, config);
|
|
44
|
+
|
|
45
|
+
native_index_t* result_ptr = new native_index_t(std::move(index));
|
|
46
|
+
std::memcpy(&result, &result_ptr, sizeof(jlong));
|
|
47
|
+
} catch (...) {
|
|
48
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
49
|
+
if (jc)
|
|
50
|
+
(*env).ThrowNew(jc, "Failed to initialize the vector index!");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
(*env).ReleaseStringUTFChars(metric, metric_cstr);
|
|
54
|
+
(*env).ReleaseStringUTFChars(accuracy, accuracy_cstr);
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1save(JNIEnv* env, jclass, jlong c_ptr, jstring path) {
|
|
59
|
+
char const* path_cstr{};
|
|
60
|
+
try {
|
|
61
|
+
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
62
|
+
reinterpret_cast<native_index_t*>(c_ptr)->save(path_cstr);
|
|
63
|
+
} catch (...) {
|
|
64
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
65
|
+
if (jc)
|
|
66
|
+
(*env).ThrowNew(jc, "Failed to dump vector index to path!");
|
|
67
|
+
}
|
|
68
|
+
(*env).ReleaseStringUTFChars(path, path_cstr);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1load(JNIEnv* env, jclass, jlong c_ptr, jstring path) {
|
|
72
|
+
char const* path_cstr{};
|
|
73
|
+
try {
|
|
74
|
+
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
75
|
+
reinterpret_cast<native_index_t*>(c_ptr)->load(path_cstr);
|
|
76
|
+
} catch (...) {
|
|
77
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
78
|
+
if (jc)
|
|
79
|
+
(*env).ThrowNew(jc, "Failed to load vector index from path!");
|
|
80
|
+
}
|
|
81
|
+
(*env).ReleaseStringUTFChars(path, path_cstr);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view(JNIEnv* env, jclass, jlong c_ptr, jstring path) {
|
|
85
|
+
char const* path_cstr{};
|
|
86
|
+
try {
|
|
87
|
+
path_cstr = (*env).GetStringUTFChars(path, 0);
|
|
88
|
+
reinterpret_cast<native_index_t*>(c_ptr)->view(path_cstr);
|
|
89
|
+
} catch (...) {
|
|
90
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
91
|
+
if (jc)
|
|
92
|
+
(*env).ThrowNew(jc, "Failed to view vector index from path!");
|
|
93
|
+
}
|
|
94
|
+
(*env).ReleaseStringUTFChars(path, path_cstr);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1destroy(JNIEnv*, jclass, jlong c_ptr) {
|
|
98
|
+
delete reinterpret_cast<native_index_t*>(c_ptr);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1size(JNIEnv*, jclass, jlong c_ptr) {
|
|
102
|
+
return reinterpret_cast<native_index_t*>(c_ptr)->size();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1connectivity(JNIEnv*, jclass, jlong c_ptr) {
|
|
106
|
+
return reinterpret_cast<native_index_t*>(c_ptr)->connectivity();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1dimensions(JNIEnv*, jclass, jlong c_ptr) {
|
|
110
|
+
return reinterpret_cast<native_index_t*>(c_ptr)->dimensions();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1capacity(JNIEnv*, jclass, jlong c_ptr) {
|
|
114
|
+
return reinterpret_cast<native_index_t*>(c_ptr)->capacity();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1reserve(JNIEnv* env, jclass, jlong c_ptr, jlong capacity) {
|
|
118
|
+
try {
|
|
119
|
+
return reinterpret_cast<native_index_t*>(c_ptr)->reserve(static_cast<std::size_t>(capacity));
|
|
120
|
+
} catch (...) {
|
|
121
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
122
|
+
if (jc)
|
|
123
|
+
(*env).ThrowNew(jc, "Failed to grow vector index!");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add( //
|
|
128
|
+
JNIEnv* env, jclass, jlong c_ptr, jint label, jfloatArray vector) {
|
|
129
|
+
|
|
130
|
+
jfloat* vector_data{};
|
|
131
|
+
try {
|
|
132
|
+
vector_data = (*env).GetFloatArrayElements(vector, 0);
|
|
133
|
+
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
134
|
+
span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
135
|
+
reinterpret_cast<native_index_t*>(c_ptr)->add(label, vector_span);
|
|
136
|
+
} catch (...) {
|
|
137
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
138
|
+
if (jc)
|
|
139
|
+
(*env).ThrowNew(jc, "Failed to insert a new point in vector index!");
|
|
140
|
+
}
|
|
141
|
+
(*env).ReleaseFloatArrayElements(vector, vector_data, 0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search( //
|
|
145
|
+
JNIEnv* env, jclass, jlong c_ptr, jfloatArray vector, jlong wanted) {
|
|
146
|
+
|
|
147
|
+
jintArray matches;
|
|
148
|
+
matches = (*env).NewIntArray(wanted);
|
|
149
|
+
if (matches == NULL)
|
|
150
|
+
return NULL;
|
|
151
|
+
|
|
152
|
+
jint* matches_data = (jint*)std::malloc(sizeof(jint) * wanted);
|
|
153
|
+
if (matches_data == NULL)
|
|
154
|
+
return NULL;
|
|
155
|
+
|
|
156
|
+
jfloat* vector_data{};
|
|
157
|
+
std::size_t found{};
|
|
158
|
+
try {
|
|
159
|
+
vector_data = (*env).GetFloatArrayElements(vector, 0);
|
|
160
|
+
jsize vector_dims = (*env).GetArrayLength(vector);
|
|
161
|
+
span_t vector_span = span_t{vector_data, static_cast<std::size_t>(vector_dims)};
|
|
162
|
+
found = reinterpret_cast<native_index_t*>(c_ptr)->search( //
|
|
163
|
+
vector_span, static_cast<std::size_t>(wanted), matches_data, NULL);
|
|
164
|
+
(*env).SetIntArrayRegion(matches, 0, found, matches_data);
|
|
165
|
+
} catch (...) {
|
|
166
|
+
jclass jc = (*env).FindClass("java/lang/Error");
|
|
167
|
+
if (jc)
|
|
168
|
+
(*env).ThrowNew(jc, "Failed to find in vector index!");
|
|
169
|
+
}
|
|
170
|
+
(*env).ReleaseFloatArrayElements(vector, vector_data, 0);
|
|
171
|
+
std::free(matches_data);
|
|
172
|
+
return matches;
|
|
173
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/* DO NOT EDIT THIS FILE - it is machine generated */
|
|
2
|
+
#include <jni.h>
|
|
3
|
+
/* Header for class cloud_unum_usearch_Index */
|
|
4
|
+
|
|
5
|
+
#ifndef _Included_cloud_unum_usearch_Index
|
|
6
|
+
#define _Included_cloud_unum_usearch_Index
|
|
7
|
+
#ifdef __cplusplus
|
|
8
|
+
extern "C" {
|
|
9
|
+
#endif
|
|
10
|
+
/*
|
|
11
|
+
* Class: cloud_unum_usearch_Index
|
|
12
|
+
* Method: c_create
|
|
13
|
+
* Signature: (Ljava/lang/String;Ljava/lang/String;JJJJJ)J
|
|
14
|
+
*/
|
|
15
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1create
|
|
16
|
+
(JNIEnv *, jclass, jstring, jstring, jlong, jlong, jlong, jlong, jlong);
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Class: cloud_unum_usearch_Index
|
|
20
|
+
* Method: c_destroy
|
|
21
|
+
* Signature: (J)V
|
|
22
|
+
*/
|
|
23
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1destroy
|
|
24
|
+
(JNIEnv *, jclass, jlong);
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* Class: cloud_unum_usearch_Index
|
|
28
|
+
* Method: c_size
|
|
29
|
+
* Signature: (J)J
|
|
30
|
+
*/
|
|
31
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1size
|
|
32
|
+
(JNIEnv *, jclass, jlong);
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* Class: cloud_unum_usearch_Index
|
|
36
|
+
* Method: c_connectivity
|
|
37
|
+
* Signature: (J)J
|
|
38
|
+
*/
|
|
39
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1connectivity
|
|
40
|
+
(JNIEnv *, jclass, jlong);
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* Class: cloud_unum_usearch_Index
|
|
44
|
+
* Method: c_dimensions
|
|
45
|
+
* Signature: (J)J
|
|
46
|
+
*/
|
|
47
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1dimensions
|
|
48
|
+
(JNIEnv *, jclass, jlong);
|
|
49
|
+
|
|
50
|
+
/*
|
|
51
|
+
* Class: cloud_unum_usearch_Index
|
|
52
|
+
* Method: c_capacity
|
|
53
|
+
* Signature: (J)J
|
|
54
|
+
*/
|
|
55
|
+
JNIEXPORT jlong JNICALL Java_cloud_unum_usearch_Index_c_1capacity
|
|
56
|
+
(JNIEnv *, jclass, jlong);
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* Class: cloud_unum_usearch_Index
|
|
60
|
+
* Method: c_reserve
|
|
61
|
+
* Signature: (JJ)V
|
|
62
|
+
*/
|
|
63
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1reserve
|
|
64
|
+
(JNIEnv *, jclass, jlong, jlong);
|
|
65
|
+
|
|
66
|
+
/*
|
|
67
|
+
* Class: cloud_unum_usearch_Index
|
|
68
|
+
* Method: c_add
|
|
69
|
+
* Signature: (JI[F)V
|
|
70
|
+
*/
|
|
71
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1add
|
|
72
|
+
(JNIEnv *, jclass, jlong, jint, jfloatArray);
|
|
73
|
+
|
|
74
|
+
/*
|
|
75
|
+
* Class: cloud_unum_usearch_Index
|
|
76
|
+
* Method: c_search
|
|
77
|
+
* Signature: (J[FJ)[I
|
|
78
|
+
*/
|
|
79
|
+
JNIEXPORT jintArray JNICALL Java_cloud_unum_usearch_Index_c_1search
|
|
80
|
+
(JNIEnv *, jclass, jlong, jfloatArray, jlong);
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Class: cloud_unum_usearch_Index
|
|
84
|
+
* Method: c_save
|
|
85
|
+
* Signature: (JLjava/lang/String;)V
|
|
86
|
+
*/
|
|
87
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1save
|
|
88
|
+
(JNIEnv *, jclass, jlong, jstring);
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
* Class: cloud_unum_usearch_Index
|
|
92
|
+
* Method: c_load
|
|
93
|
+
* Signature: (JLjava/lang/String;)V
|
|
94
|
+
*/
|
|
95
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1load
|
|
96
|
+
(JNIEnv *, jclass, jlong, jstring);
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* Class: cloud_unum_usearch_Index
|
|
100
|
+
* Method: c_view
|
|
101
|
+
* Signature: (JLjava/lang/String;)V
|
|
102
|
+
*/
|
|
103
|
+
JNIEXPORT void JNICALL Java_cloud_unum_usearch_Index_c_1view
|
|
104
|
+
(JNIEnv *, jclass, jlong, jstring);
|
|
105
|
+
|
|
106
|
+
#ifdef __cplusplus
|
|
107
|
+
}
|
|
108
|
+
#endif
|
|
109
|
+
#endif
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import java.io.File;
|
|
2
|
+
import java.util.Arrays;
|
|
3
|
+
|
|
4
|
+
import org.junit.Test;
|
|
5
|
+
|
|
6
|
+
import cloud.unum.usearch.Index;
|
|
7
|
+
|
|
8
|
+
public class IndexTest {
|
|
9
|
+
|
|
10
|
+
public static void deleteDirectoryFiles(String path) {
|
|
11
|
+
File directory = new File(path);
|
|
12
|
+
if (!directory.isDirectory())
|
|
13
|
+
return;
|
|
14
|
+
|
|
15
|
+
for (File f : directory.listFiles())
|
|
16
|
+
f.delete();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Test
|
|
20
|
+
public void test() {
|
|
21
|
+
String path = "./tmp/";
|
|
22
|
+
deleteDirectoryFiles(path);
|
|
23
|
+
new Index();
|
|
24
|
+
System.out.println("Java Tests Passed!");
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usearch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "The Mighty Tiny Vector Search Engine with Automatic Quantization and Hardware Acceleration",
|
|
5
5
|
"author": "Ashot Vardanian",
|
|
6
6
|
"license": "Apache 2.0",
|
|
@@ -17,6 +17,6 @@
|
|
|
17
17
|
"node-addon-api": "^3.0.0"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"test": "node
|
|
20
|
+
"test": "node javascript/test.js"
|
|
21
21
|
}
|
|
22
22
|
}
|
package/pom.xml
ADDED
|
@@ -47,30 +47,8 @@ static native_index_t make_index( //
|
|
|
47
47
|
config.max_threads_add = std::thread::hardware_concurrency();
|
|
48
48
|
config.max_threads_search = std::thread::hardware_concurrency();
|
|
49
49
|
|
|
50
|
-
accuracy_t accuracy;
|
|
51
|
-
|
|
52
|
-
accuracy = accuracy_t::f32_k;
|
|
53
|
-
else if (scalar_type == "f64")
|
|
54
|
-
accuracy = accuracy_t::f64_k;
|
|
55
|
-
else if (scalar_type == "f16")
|
|
56
|
-
accuracy = accuracy_t::f16_k;
|
|
57
|
-
else if (scalar_type == "i8q100")
|
|
58
|
-
accuracy = accuracy_t::i8q100_k;
|
|
59
|
-
else
|
|
60
|
-
throw std::runtime_error("Unknown type, choose: f32, f16, f64, i8q100");
|
|
61
|
-
|
|
62
|
-
if (metric == "l2_sq" || metric == "euclidean_sq")
|
|
63
|
-
return native_index_t::l2(dimensions, accuracy, config);
|
|
64
|
-
else if (metric == "ip" || metric == "inner" || metric == "dot")
|
|
65
|
-
return native_index_t::ip(dimensions, accuracy, config);
|
|
66
|
-
else if (metric == "cos" || metric == "angular")
|
|
67
|
-
return native_index_t::cos(dimensions, accuracy, config);
|
|
68
|
-
else if (metric == "haversine")
|
|
69
|
-
return native_index_t::haversine(accuracy, config);
|
|
70
|
-
else
|
|
71
|
-
throw std::runtime_error("Unknown distance, choose: l2_sq, ip, cos, hamming, jaccard");
|
|
72
|
-
|
|
73
|
-
return {};
|
|
50
|
+
accuracy_t accuracy = accuracy_from_name(scalar_type.c_str(), scalar_type.size());
|
|
51
|
+
return index_from_name<native_index_t>(metric.c_str(), metric.size(), dimensions, accuracy, config);
|
|
74
52
|
}
|
|
75
53
|
|
|
76
54
|
static void add_to_index(native_index_t& index, py::buffer labels, py::buffer vectors, bool copy) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#include "
|
|
2
|
-
#include "usearch/
|
|
1
|
+
#include "lib.hpp"
|
|
2
|
+
#include "usearch/rust/lib.rs.h"
|
|
3
3
|
|
|
4
4
|
using namespace unum::usearch;
|
|
5
5
|
using namespace unum;
|
|
@@ -40,7 +40,7 @@ void Index::save(rust::Str path) const { index_->save(std::string(path).c_str())
|
|
|
40
40
|
void Index::load(rust::Str path) const { index_->load(std::string(path).c_str()); }
|
|
41
41
|
void Index::view(rust::Str path) const { index_->view(std::string(path).c_str()); }
|
|
42
42
|
|
|
43
|
-
accuracy_t accuracy(rust::Str quant) { return
|
|
43
|
+
accuracy_t accuracy(rust::Str quant) { return accuracy_from_name(quant.data(), quant.size()); }
|
|
44
44
|
|
|
45
45
|
std::unique_ptr<Index> wrap(native_index_t&& index) {
|
|
46
46
|
std::shared_ptr<native_index_t> native = std::make_shared<native_index_t>(std::move(index));
|
package/{src → rust}/lib.rs
RENAMED
package/setup.py
CHANGED
|
@@ -12,7 +12,7 @@ if sys.platform == 'darwin':
|
|
|
12
12
|
ext_modules = [
|
|
13
13
|
Pybind11Extension(
|
|
14
14
|
'usearch',
|
|
15
|
-
['
|
|
15
|
+
['python/lib.cpp'],
|
|
16
16
|
extra_compile_args=compile_args,
|
|
17
17
|
),
|
|
18
18
|
]
|
|
@@ -58,6 +58,6 @@ setup(
|
|
|
58
58
|
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
|
59
59
|
],
|
|
60
60
|
|
|
61
|
-
include_dirs=['include', 'fp16/include', 'simsimd/include'],
|
|
61
|
+
include_dirs=['include', 'fp16/include', 'simsimd/include', 'src'],
|
|
62
62
|
ext_modules=ext_modules,
|
|
63
63
|
)
|
package/src/advanced.hpp
CHANGED
|
@@ -172,26 +172,43 @@ enum class accuracy_t {
|
|
|
172
172
|
i8q100_k,
|
|
173
173
|
};
|
|
174
174
|
|
|
175
|
-
inline bool str_equals(char const* begin, size_t len, char const* other_begin) noexcept {
|
|
176
|
-
size_t other_len = strlen(other_begin);
|
|
175
|
+
inline bool str_equals(char const* begin, std::size_t len, char const* other_begin) noexcept {
|
|
176
|
+
std::size_t other_len = strlen(other_begin);
|
|
177
177
|
return len == other_len && strncmp(begin, other_begin, len) == 0;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
inline accuracy_t
|
|
180
|
+
inline accuracy_t accuracy_from_name(char const* name, std::size_t len) {
|
|
181
181
|
accuracy_t accuracy;
|
|
182
|
-
if (str_equals(
|
|
182
|
+
if (str_equals(name, len, "f32"))
|
|
183
183
|
accuracy = accuracy_t::f32_k;
|
|
184
|
-
else if (str_equals(
|
|
184
|
+
else if (str_equals(name, len, "f64"))
|
|
185
185
|
accuracy = accuracy_t::f64_k;
|
|
186
|
-
else if (str_equals(
|
|
186
|
+
else if (str_equals(name, len, "f16"))
|
|
187
187
|
accuracy = accuracy_t::f16_k;
|
|
188
|
-
else if (str_equals(
|
|
188
|
+
else if (str_equals(name, len, "i8q100"))
|
|
189
189
|
accuracy = accuracy_t::i8q100_k;
|
|
190
190
|
else
|
|
191
191
|
throw std::runtime_error("Unknown type, choose: f32, f16, f64, i8q100");
|
|
192
192
|
return accuracy;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
template <typename index_at>
|
|
196
|
+
inline index_at index_from_name( //
|
|
197
|
+
char const* name, std::size_t len, std::size_t dimensions, accuracy_t accuracy, config_t const& config) {
|
|
198
|
+
|
|
199
|
+
if (str_equals(name, len, "l2_sq") || str_equals(name, len, "euclidean_sq"))
|
|
200
|
+
return index_at::l2(dimensions, accuracy, config);
|
|
201
|
+
else if (str_equals(name, len, "ip") || str_equals(name, len, "inner") || str_equals(name, len, "dot"))
|
|
202
|
+
return index_at::ip(dimensions, accuracy, config);
|
|
203
|
+
else if (str_equals(name, len, "cos") || str_equals(name, len, "angular"))
|
|
204
|
+
return index_at::cos(dimensions, accuracy, config);
|
|
205
|
+
else if (str_equals(name, len, "haversine"))
|
|
206
|
+
return index_at::haversine(accuracy, config);
|
|
207
|
+
else
|
|
208
|
+
throw std::runtime_error("Unknown distance, choose: l2_sq, ip, cos, hamming, jaccard");
|
|
209
|
+
return {};
|
|
210
|
+
}
|
|
211
|
+
|
|
195
212
|
enum class isa_t {
|
|
196
213
|
auto_k,
|
|
197
214
|
neon_k,
|
package/wolfram/lib.cpp
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#include "WolframLibrary.h"
|
|
2
|
+
|
|
3
|
+
EXTERN_C DLLEXPORT mint WolframLibrary_getVersion() { return WolframLibraryVersion; }
|
|
4
|
+
EXTERN_C DLLEXPORT int WolframLibrary_initialize(WolframLibraryData libData) { return 0; }
|
|
5
|
+
EXTERN_C DLLEXPORT void WolframLibrary_uninitialize(WolframLibraryData libData) { return; }
|
|
6
|
+
|
|
7
|
+
EXTERN_C DLLEXPORT int IndexInit(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
8
|
+
return LIBRARY_NO_ERROR;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
EXTERN_C DLLEXPORT int IndexReserve(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
12
|
+
return LIBRARY_NO_ERROR;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
EXTERN_C DLLEXPORT int IndexAdd(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
16
|
+
return LIBRARY_NO_ERROR;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
EXTERN_C DLLEXPORT int IndexSearch(WolframLibraryData libData, mint Argc, MArgument* Args, MArgument Res) {
|
|
20
|
+
return LIBRARY_NO_ERROR;
|
|
21
|
+
}
|
|
File without changes
|
|
File without changes
|
/package/{src → python}/bench.py
RENAMED
|
File without changes
|
/package/{src → python}/test.py
RENAMED
|
File without changes
|
|
File without changes
|