@delali/narsil-react-native 0.0.0-stage → 0.3.1-next.151
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/LICENSE +201 -0
- package/NarsilReactNative.podspec +57 -0
- package/README.md +46 -2
- package/android/CMakeLists.txt +48 -0
- package/android/build.gradle +151 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/AndroidEnvironment.cpp +44 -0
- package/android/src/main/cpp/AndroidEnvironment.hpp +11 -0
- package/android/src/main/cpp/cpp-adapter.cpp +11 -0
- package/android/src/main/java/com/margelo/nitro/narsil/NarsilAndroidEnvironment.kt +29 -0
- package/android/src/main/java/com/margelo/nitro/narsil/NarsilReactNativePackage.kt +22 -0
- package/app.plugin.js +25 -0
- package/cpp/AttachedField.cpp +234 -0
- package/cpp/AttachedField.hpp +61 -0
- package/cpp/Compression.cpp +113 -0
- package/cpp/Compression.hpp +16 -0
- package/cpp/GraphHeldAlone.cpp +29 -0
- package/cpp/GraphHeldAlone.hpp +25 -0
- package/cpp/HostMemory.cpp +123 -0
- package/cpp/HostMemory.hpp +53 -0
- package/cpp/HybridNarsilCoreImpl.cpp +390 -0
- package/cpp/HybridNarsilCoreImpl.hpp +68 -0
- package/cpp/HybridNarsilFilesImpl.cpp +245 -0
- package/cpp/HybridNarsilFilesImpl.hpp +34 -0
- package/cpp/HybridNarsilHostImpl.cpp +126 -0
- package/cpp/HybridNarsilHostImpl.hpp +42 -0
- package/cpp/NativeAtomics.cpp +110 -0
- package/cpp/NativeAtomics.hpp +11 -0
- package/cpp/ProcessInfo.cpp +83 -0
- package/cpp/ProcessInfo.hpp +11 -0
- package/cpp/ThreadPriority.cpp +77 -0
- package/cpp/ThreadPriority.hpp +8 -0
- package/cpp/WorkletRuntimeDispatcher.cpp +61 -0
- package/cpp/WorkletRuntimeDispatcher.hpp +9 -0
- package/cpp/core/include/narsil_core.h +208 -0
- package/cpp/core/src/connect.c +213 -0
- package/cpp/core/src/distance.c +103 -0
- package/cpp/core/src/files.c +99 -0
- package/cpp/core/src/heap.c +84 -0
- package/cpp/core/src/internal.h +284 -0
- package/cpp/core/src/kernels_code.c +209 -0
- package/cpp/core/src/kernels_float.c +197 -0
- package/cpp/core/src/kernels_pair.c +133 -0
- package/cpp/core/src/last_links.c +145 -0
- package/cpp/core/src/links.c +195 -0
- package/cpp/core/src/locks.c +168 -0
- package/cpp/core/src/nearest_links.c +147 -0
- package/cpp/core/src/place.c +215 -0
- package/cpp/core/src/quantize.c +226 -0
- package/cpp/core/src/records.c +97 -0
- package/cpp/core/src/remove.c +205 -0
- package/cpp/core/src/vectors.c +139 -0
- package/cpp/core/src/walk.c +231 -0
- package/cpp/core/src/workspace.c +167 -0
- package/ios/PrivacyInfo.xcprivacy +23 -0
- package/lib/client.d.ts +19 -0
- package/lib/client.js +41 -0
- package/lib/constants.d.ts +9 -0
- package/lib/constants.js +9 -0
- package/lib/engine/byte-files.d.ts +5 -0
- package/lib/engine/byte-files.js +97 -0
- package/lib/engine/core.d.ts +3 -0
- package/lib/engine/core.js +113 -0
- package/lib/engine/files.d.ts +3 -0
- package/lib/engine/files.js +188 -0
- package/lib/engine/host.d.ts +13 -0
- package/lib/engine/host.js +102 -0
- package/lib/engine/install.d.ts +4 -0
- package/lib/engine/install.js +29 -0
- package/lib/engine/native-error.d.ts +1 -0
- package/lib/engine/native-error.js +12 -0
- package/lib/engine/stand-ins/atomics.d.ts +5 -0
- package/lib/engine/stand-ins/atomics.js +236 -0
- package/lib/engine/stand-ins/crypto.d.ts +2 -0
- package/lib/engine/stand-ins/crypto.js +65 -0
- package/lib/engine/stand-ins/process.d.ts +2 -0
- package/lib/engine/stand-ins/process.js +22 -0
- package/lib/engine/stand-ins/streams.d.ts +1 -0
- package/lib/engine/stand-ins/streams.js +31 -0
- package/lib/engine/stand-ins/structured-clone.d.ts +1 -0
- package/lib/engine/stand-ins/structured-clone.js +121 -0
- package/lib/engine/streamed.d.ts +6 -0
- package/lib/engine/streamed.js +29 -0
- package/lib/engine/transfer.d.ts +3 -0
- package/lib/engine/transfer.js +77 -0
- package/lib/errors.d.ts +25 -0
- package/lib/errors.js +59 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +2 -0
- package/lib/methods.d.ts +5 -0
- package/lib/methods.js +47 -0
- package/lib/native-objects.d.ts +2 -0
- package/lib/native-objects.js +24 -0
- package/lib/specs/core.nitro.d.ts +79 -0
- package/lib/specs/core.nitro.js +1 -0
- package/lib/specs/files.nitro.d.ts +36 -0
- package/lib/specs/files.nitro.js +1 -0
- package/lib/specs/host.nitro.d.ts +24 -0
- package/lib/specs/host.nitro.js +1 -0
- package/lib/transferred.d.ts +15 -0
- package/lib/transferred.js +6 -0
- package/lib/types.d.ts +136 -0
- package/lib/types.js +1 -0
- package/lib/worklets/app-turns.d.ts +1 -0
- package/lib/worklets/app-turns.js +44 -0
- package/lib/worklets/client.d.ts +30 -0
- package/lib/worklets/client.js +144 -0
- package/lib/worklets/index.d.ts +4 -0
- package/lib/worklets/index.js +2 -0
- package/lib/worklets/instances.d.ts +15 -0
- package/lib/worklets/instances.js +194 -0
- package/lib/worklets/json-part.d.ts +1 -0
- package/lib/worklets/json-part.js +42 -0
- package/lib/worklets/runtime.d.ts +25 -0
- package/lib/worklets/runtime.js +80 -0
- package/lib/worklets/transfer-queue.d.ts +7 -0
- package/lib/worklets/transfer-queue.js +79 -0
- package/lib/worklets/types.d.ts +26 -0
- package/lib/worklets/types.js +1 -0
- package/nitro.json +32 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/NarsilReactNative+autolinking.cmake +85 -0
- package/nitrogen/generated/android/NarsilReactNative+autolinking.gradle +27 -0
- package/nitrogen/generated/android/NarsilReactNativeOnLoad.cpp +69 -0
- package/nitrogen/generated/android/NarsilReactNativeOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/narsil/NarsilReactNativeOnLoad.kt +35 -0
- package/nitrogen/generated/ios/NarsilReactNative+autolinking.rb +62 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/NarsilReactNativeAutolinking.mm +55 -0
- package/nitrogen/generated/ios/NarsilReactNativeAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/DirectoryEntry.hpp +91 -0
- package/nitrogen/generated/shared/c++/FileStatus.hpp +103 -0
- package/nitrogen/generated/shared/c++/GraphMemory.hpp +120 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.hpp +62 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +35 -0
- package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +100 -0
- package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.cpp +37 -0
- package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.hpp +86 -0
- package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.cpp +34 -0
- package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.hpp +78 -0
- package/nitrogen/generated/shared/c++/MemoryView.hpp +91 -0
- package/nitrogen/generated/shared/c++/NativeConnectOutcome.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeScores.hpp +87 -0
- package/nitrogen/generated/shared/c++/NativeSearchHits.hpp +91 -0
- package/nitrogen/generated/shared/c++/ProcessMemory.hpp +87 -0
- package/nitrogen/generated/shared/c++/StoreMemory.hpp +142 -0
- package/package.json +87 -3
- package/react-native.config.js +8 -0
- package/src/client.ts +44 -0
- package/src/constants.ts +9 -0
- package/src/engine/byte-files.ts +99 -0
- package/src/engine/core.ts +162 -0
- package/src/engine/files.ts +186 -0
- package/src/engine/host.ts +111 -0
- package/src/engine/install.ts +31 -0
- package/src/engine/native-error.ts +10 -0
- package/src/engine/stand-ins/atomics.ts +288 -0
- package/src/engine/stand-ins/crypto.ts +81 -0
- package/src/engine/stand-ins/process.ts +30 -0
- package/src/engine/stand-ins/streams.ts +45 -0
- package/src/engine/stand-ins/structured-clone.ts +118 -0
- package/src/engine/streamed.ts +40 -0
- package/src/engine/transfer.ts +72 -0
- package/src/errors.ts +73 -0
- package/src/index.ts +3 -0
- package/src/methods.ts +52 -0
- package/src/native-objects.ts +30 -0
- package/src/specs/core.nitro.ts +140 -0
- package/src/specs/files.nitro.ts +42 -0
- package/src/specs/host.nitro.ts +30 -0
- package/src/transferred.ts +18 -0
- package/src/types.ts +164 -0
- package/src/worklets/app-turns.ts +48 -0
- package/src/worklets/client.ts +165 -0
- package/src/worklets/index.ts +4 -0
- package/src/worklets/instances.ts +231 -0
- package/src/worklets/json-part.ts +38 -0
- package/src/worklets/runtime.ts +190 -0
- package/src/worklets/transfer-queue.ts +98 -0
- package/src/worklets/types.ts +37 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#include "HybridNarsilCoreImpl.hpp"
|
|
2
|
+
#include "AttachedField.hpp"
|
|
3
|
+
#include "GraphHeldAlone.hpp"
|
|
4
|
+
#include "HostMemory.hpp"
|
|
5
|
+
|
|
6
|
+
#include <atomic>
|
|
7
|
+
#include <cerrno>
|
|
8
|
+
#include <cmath>
|
|
9
|
+
#include <cstdint>
|
|
10
|
+
#include <memory>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
|
|
14
|
+
namespace margelo::nitro::narsil {
|
|
15
|
+
|
|
16
|
+
namespace {
|
|
17
|
+
|
|
18
|
+
constexpr uint32_t MEASURE_TOTALS_PAST_DIMENSION = 2;
|
|
19
|
+
constexpr uint32_t BACKGROUND_THREAD_SLOT_LIMIT = 64;
|
|
20
|
+
const uint8_t NO_ACCEPTED_ORDINAL = 0;
|
|
21
|
+
|
|
22
|
+
template <typename Element>
|
|
23
|
+
Element* elementsOf(const MemoryView& view, size_t minimum, const char* what, size_t* count = nullptr) {
|
|
24
|
+
uint8_t* bytes = bytesWithin(view.buffer, view.byteOffset, view.byteLength, what);
|
|
25
|
+
size_t elements = static_cast<size_t>(view.byteLength) / sizeof(Element);
|
|
26
|
+
if ((bytes == nullptr && minimum > 0) || reinterpret_cast<uintptr_t>(bytes) % alignof(Element) != 0 ||
|
|
27
|
+
static_cast<size_t>(view.byteLength) % sizeof(Element) != 0 || elements < minimum) {
|
|
28
|
+
throwInvalid(std::string(what) + " has the wrong type, alignment, or length");
|
|
29
|
+
}
|
|
30
|
+
if (count != nullptr) *count = elements;
|
|
31
|
+
return reinterpret_cast<Element*>(bytes);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
uint32_t unsignedOf(double value, const char* what) {
|
|
35
|
+
if (!std::isfinite(value) || value < 0 || value > UINT32_MAX || std::floor(value) != value) {
|
|
36
|
+
throwInvalid(std::string(what) + " must be a whole number from 0 to 4294967295");
|
|
37
|
+
}
|
|
38
|
+
return static_cast<uint32_t>(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
int32_t signedOf(double value, const char* what) {
|
|
42
|
+
if (!std::isfinite(value) || value < INT32_MIN || value > INT32_MAX || std::floor(value) != value) {
|
|
43
|
+
throwInvalid(std::string(what) + " must be a 32-bit whole number");
|
|
44
|
+
}
|
|
45
|
+
return static_cast<int32_t>(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
uint32_t clampedCount(size_t count) { return count > UINT32_MAX ? UINT32_MAX : static_cast<uint32_t>(count); }
|
|
49
|
+
|
|
50
|
+
double statusOf(narsil_status status) { return static_cast<double>(status); }
|
|
51
|
+
|
|
52
|
+
class BackgroundUse {
|
|
53
|
+
public:
|
|
54
|
+
BackgroundUse(std::shared_ptr<HybridNarsilCoreImpl> core, std::shared_ptr<HybridNarsilAttachedStoreImpl> store,
|
|
55
|
+
uint32_t threadSlot, narsil_workspace* workspace)
|
|
56
|
+
: workspace(workspace), _core(std::move(core)), _store(std::move(store)), _threadSlot(threadSlot) {}
|
|
57
|
+
~BackgroundUse() { release(); }
|
|
58
|
+
BackgroundUse(const BackgroundUse&) = delete;
|
|
59
|
+
BackgroundUse& operator=(const BackgroundUse&) = delete;
|
|
60
|
+
|
|
61
|
+
void release() {
|
|
62
|
+
if (_released.exchange(true)) return;
|
|
63
|
+
_store->endBackgroundUse();
|
|
64
|
+
_core->releaseBackgroundSlot(_threadSlot);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
narsil_workspace* const workspace;
|
|
68
|
+
|
|
69
|
+
private:
|
|
70
|
+
std::shared_ptr<HybridNarsilCoreImpl> _core;
|
|
71
|
+
std::shared_ptr<HybridNarsilAttachedStoreImpl> _store;
|
|
72
|
+
uint32_t _threadSlot;
|
|
73
|
+
std::atomic<bool> _released{false};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
class ReleaseWhenDone {
|
|
77
|
+
public:
|
|
78
|
+
explicit ReleaseWhenDone(std::shared_ptr<BackgroundUse> use) : _use(std::move(use)) {}
|
|
79
|
+
~ReleaseWhenDone() { _use->release(); }
|
|
80
|
+
ReleaseWhenDone(const ReleaseWhenDone&) = delete;
|
|
81
|
+
ReleaseWhenDone& operator=(const ReleaseWhenDone&) = delete;
|
|
82
|
+
|
|
83
|
+
private:
|
|
84
|
+
std::shared_ptr<BackgroundUse> _use;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
std::shared_ptr<BackgroundUse> startBackgroundUse(const std::shared_ptr<HybridNarsilCoreImpl>& core,
|
|
88
|
+
const std::shared_ptr<HybridNarsilAttachedStoreImpl>& store,
|
|
89
|
+
uint32_t threadSlot) {
|
|
90
|
+
narsil_workspace* workspace = core->claimBackgroundSlot(threadSlot);
|
|
91
|
+
if (!store->beginBackgroundUse()) {
|
|
92
|
+
core->releaseBackgroundSlot(threadSlot);
|
|
93
|
+
throwInvalid("The vector store is detached");
|
|
94
|
+
}
|
|
95
|
+
return std::make_shared<BackgroundUse>(core, store, threadSlot, workspace);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
std::shared_ptr<std::vector<float>> copiedQuery(const MemoryView& query, uint32_t dimension) {
|
|
99
|
+
size_t queryLength = 0;
|
|
100
|
+
const float* values = elementsOf<float>(query, 1, "The query", &queryLength);
|
|
101
|
+
if (queryLength != dimension) throwInvalid("The query has the wrong dimension");
|
|
102
|
+
return std::make_shared<std::vector<float>>(values, values + queryLength);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
std::shared_ptr<ArrayBuffer> allocatedFor(size_t count, size_t elementBytes) {
|
|
106
|
+
return ArrayBuffer::allocate((count == 0 ? 1 : count) * elementBytes);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
HybridNarsilCoreImpl::~HybridNarsilCoreImpl() {
|
|
112
|
+
if (_workspace != nullptr) narsil_workspace_destroy(_workspace);
|
|
113
|
+
for (auto& entry : _backgroundWorkspaces) narsil_workspace_destroy(entry.second);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
narsil_workspace* HybridNarsilCoreImpl::claimBackgroundSlot(uint32_t threadSlot) {
|
|
117
|
+
std::lock_guard<std::mutex> guard(_backgroundLock);
|
|
118
|
+
if (_busyBackgroundSlots.count(threadSlot) != 0) throwInvalid("The thread slot is already searching");
|
|
119
|
+
auto found = _backgroundWorkspaces.find(threadSlot);
|
|
120
|
+
narsil_workspace* claimed = found == _backgroundWorkspaces.end() ? nullptr : found->second;
|
|
121
|
+
if (claimed == nullptr) {
|
|
122
|
+
if (narsil_workspace_create(&claimed) != NARSIL_OK) {
|
|
123
|
+
throwSystemError(ENOMEM, "allocate a background search workspace", "");
|
|
124
|
+
}
|
|
125
|
+
_backgroundWorkspaces.emplace(threadSlot, claimed);
|
|
126
|
+
}
|
|
127
|
+
_busyBackgroundSlots.insert(threadSlot);
|
|
128
|
+
return claimed;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
void HybridNarsilCoreImpl::releaseBackgroundSlot(uint32_t threadSlot) {
|
|
132
|
+
std::lock_guard<std::mutex> guard(_backgroundLock);
|
|
133
|
+
_busyBackgroundSlots.erase(threadSlot);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
narsil_workspace* HybridNarsilCoreImpl::workspace() {
|
|
137
|
+
if (_workspace == nullptr && narsil_workspace_create(&_workspace) != NARSIL_OK) {
|
|
138
|
+
_workspace = nullptr;
|
|
139
|
+
throwSystemError(ENOMEM, "allocate the search workspace", "");
|
|
140
|
+
}
|
|
141
|
+
return _workspace;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
double HybridNarsilCoreImpl::abiVersion() { return narsil_core_abi_version(); }
|
|
145
|
+
|
|
146
|
+
double HybridNarsilCoreImpl::workspaceBytes() { return static_cast<double>(narsil_workspace_bytes(workspace())); }
|
|
147
|
+
|
|
148
|
+
std::shared_ptr<HybridNarsilAttachedGraphSpec> HybridNarsilCoreImpl::attachGraph(const GraphMemory& memory) {
|
|
149
|
+
return std::make_shared<HybridNarsilAttachedGraphImpl>(memory);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
std::shared_ptr<HybridNarsilAttachedStoreSpec> HybridNarsilCoreImpl::attachStore(const StoreMemory& memory) {
|
|
153
|
+
return std::make_shared<HybridNarsilAttachedStoreImpl>(memory);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
double HybridNarsilCoreImpl::search(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
157
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store,
|
|
158
|
+
const MemoryView& query, double metric, double candidateCount, double threadSlot,
|
|
159
|
+
const MemoryView& ordinals, const MemoryView& distances,
|
|
160
|
+
const MemoryView& accepted, bool filtered) {
|
|
161
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
162
|
+
auto attachedStore = attachedStoreOf(store);
|
|
163
|
+
narsil_search_request request{};
|
|
164
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
165
|
+
request.candidate_count = unsignedOf(candidateCount, "The candidate count");
|
|
166
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
167
|
+
size_t queryLength = 0;
|
|
168
|
+
request.query = elementsOf<float>(query, 1, "The query", &queryLength);
|
|
169
|
+
if (queryLength != attachedStore->store.dimension) throwInvalid("The query has the wrong dimension");
|
|
170
|
+
size_t ordinalCapacity = 0;
|
|
171
|
+
size_t distanceCapacity = 0;
|
|
172
|
+
int32_t* ordinalOut = elementsOf<int32_t>(ordinals, 1, "The ordinals", &ordinalCapacity);
|
|
173
|
+
double* distanceOut = elementsOf<double>(distances, 1, "The distances", &distanceCapacity);
|
|
174
|
+
uint32_t capacity = clampedCount(ordinalCapacity < distanceCapacity ? ordinalCapacity : distanceCapacity);
|
|
175
|
+
if (capacity < request.candidate_count) throwInvalid("The result arrays hold fewer entries than the candidates");
|
|
176
|
+
if (filtered) {
|
|
177
|
+
size_t acceptedBytes = 0;
|
|
178
|
+
uint8_t* bits = elementsOf<uint8_t>(accepted, 0, "The accepted ordinals", &acceptedBytes);
|
|
179
|
+
request.accepted.bits = acceptedBytes == 0 ? &NO_ACCEPTED_ORDINAL : bits;
|
|
180
|
+
request.accepted.bytes = clampedCount(acceptedBytes);
|
|
181
|
+
}
|
|
182
|
+
narsil_candidates nearest{ordinalOut, distanceOut, capacity, 0};
|
|
183
|
+
narsil_status status = narsil_search(workspace(), &attachedGraph->graph, &attachedStore->store, &request, &nearest);
|
|
184
|
+
if (status != NARSIL_OK) return -statusOf(status);
|
|
185
|
+
return static_cast<double>(nearest.count);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
double HybridNarsilCoreImpl::score(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store,
|
|
189
|
+
const MemoryView& query, double metric, const MemoryView& ordinals, double count,
|
|
190
|
+
const MemoryView& distances) {
|
|
191
|
+
auto attachedStore = attachedStoreOf(store);
|
|
192
|
+
narsil_score_request request{};
|
|
193
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
194
|
+
request.count = unsignedOf(count, "The count");
|
|
195
|
+
size_t queryLength = 0;
|
|
196
|
+
request.query = elementsOf<float>(query, 1, "The query", &queryLength);
|
|
197
|
+
if (queryLength != attachedStore->store.dimension) throwInvalid("The query has the wrong dimension");
|
|
198
|
+
request.ordinals = elementsOf<int32_t>(ordinals, request.count, "The ordinals");
|
|
199
|
+
double* out = elementsOf<double>(distances, request.count, "The distances");
|
|
200
|
+
return statusOf(narsil_score(workspace(), &attachedStore->store, &request, out));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
std::shared_ptr<Promise<NativeSearchHits>> HybridNarsilCoreImpl::searchAsync(
|
|
204
|
+
const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
205
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, const MemoryView& query, double metric,
|
|
206
|
+
double candidateCount, double threadSlot, const MemoryView& accepted, bool filtered) {
|
|
207
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
208
|
+
auto attachedStore = attachedStoreOf(store);
|
|
209
|
+
narsil_search_request request{};
|
|
210
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
211
|
+
request.candidate_count = unsignedOf(candidateCount, "The candidate count");
|
|
212
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
213
|
+
if (request.candidate_count == 0) throwInvalid("The candidate count must be at least 1");
|
|
214
|
+
if (request.thread_slot >= attachedGraph->graph.thread_slots) throwInvalid("The thread slot is out of range");
|
|
215
|
+
auto queryValues = copiedQuery(query, attachedStore->store.dimension);
|
|
216
|
+
auto acceptedBits = std::make_shared<std::vector<uint8_t>>();
|
|
217
|
+
if (filtered) {
|
|
218
|
+
size_t acceptedBytes = 0;
|
|
219
|
+
uint8_t* bits = elementsOf<uint8_t>(accepted, 0, "The accepted ordinals", &acceptedBytes);
|
|
220
|
+
if (acceptedBytes > 0) acceptedBits->assign(bits, bits + acceptedBytes);
|
|
221
|
+
}
|
|
222
|
+
auto use = startBackgroundUse(shared_cast<HybridNarsilCoreImpl>(), attachedStore, request.thread_slot);
|
|
223
|
+
return Promise<NativeSearchHits>::async([use, attachedGraph, attachedStore, request, queryValues, acceptedBits,
|
|
224
|
+
filtered]() mutable {
|
|
225
|
+
ReleaseWhenDone done(use);
|
|
226
|
+
request.query = queryValues->data();
|
|
227
|
+
if (filtered) {
|
|
228
|
+
request.accepted.bits = acceptedBits->empty() ? &NO_ACCEPTED_ORDINAL : acceptedBits->data();
|
|
229
|
+
request.accepted.bytes = clampedCount(acceptedBits->size());
|
|
230
|
+
}
|
|
231
|
+
size_t capacity = request.candidate_count;
|
|
232
|
+
auto ordinals = allocatedFor(capacity, sizeof(int32_t));
|
|
233
|
+
auto distances = allocatedFor(capacity, sizeof(double));
|
|
234
|
+
narsil_candidates nearest{reinterpret_cast<int32_t*>(ordinals->data()),
|
|
235
|
+
reinterpret_cast<double*>(distances->data()), request.candidate_count, 0};
|
|
236
|
+
narsil_status status =
|
|
237
|
+
narsil_search(use->workspace, &attachedGraph->graph, &attachedStore->store, &request, &nearest);
|
|
238
|
+
double count = status == NARSIL_OK ? static_cast<double>(nearest.count) : -statusOf(status);
|
|
239
|
+
return NativeSearchHits(count, ordinals, distances);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
std::shared_ptr<Promise<NativeScores>> HybridNarsilCoreImpl::scoreAsync(
|
|
244
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, const MemoryView& query, double metric,
|
|
245
|
+
const MemoryView& ordinals, double count, double threadSlot) {
|
|
246
|
+
auto attachedStore = attachedStoreOf(store);
|
|
247
|
+
narsil_score_request request{};
|
|
248
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
249
|
+
request.count = unsignedOf(count, "The count");
|
|
250
|
+
uint32_t slot = unsignedOf(threadSlot, "The thread slot");
|
|
251
|
+
if (slot >= BACKGROUND_THREAD_SLOT_LIMIT) throwInvalid("The thread slot is out of range");
|
|
252
|
+
auto queryValues = copiedQuery(query, attachedStore->store.dimension);
|
|
253
|
+
const int32_t* chosen = elementsOf<int32_t>(ordinals, request.count, "The ordinals");
|
|
254
|
+
auto chosenOrdinals = std::make_shared<std::vector<int32_t>>(chosen, chosen + request.count);
|
|
255
|
+
auto use = startBackgroundUse(shared_cast<HybridNarsilCoreImpl>(), attachedStore, slot);
|
|
256
|
+
return Promise<NativeScores>::async([use, attachedStore, request, queryValues, chosenOrdinals]() mutable {
|
|
257
|
+
ReleaseWhenDone done(use);
|
|
258
|
+
request.query = queryValues->data();
|
|
259
|
+
request.ordinals = chosenOrdinals->data();
|
|
260
|
+
auto distances = allocatedFor(request.count, sizeof(double));
|
|
261
|
+
narsil_status status = narsil_score(use->workspace, &attachedStore->store, &request,
|
|
262
|
+
reinterpret_cast<double*>(distances->data()));
|
|
263
|
+
return NativeScores(statusOf(status), distances);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
double HybridNarsilCoreImpl::place(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
268
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
269
|
+
double ordinal, double topLayer, double graphHeldAlone, double threadSlot,
|
|
270
|
+
const MemoryView& wakes) {
|
|
271
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
272
|
+
auto attachedStore = attachedStoreOf(store);
|
|
273
|
+
narsil_place_request request{};
|
|
274
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
275
|
+
request.ordinal = signedOf(ordinal, "The ordinal");
|
|
276
|
+
request.top_layer = signedOf(topLayer, "The top layer");
|
|
277
|
+
request.graph_held_alone = unsignedOf(graphHeldAlone, "The graph lock flag");
|
|
278
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
279
|
+
attachedGraph->wakes.count = 0;
|
|
280
|
+
narsil_status status = narsil_place(workspace(), &attachedGraph->graph, &attachedStore->store, &request);
|
|
281
|
+
handOverWakes(attachedGraph->wakes, wakes);
|
|
282
|
+
return statusOf(status);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
double HybridNarsilCoreImpl::remove(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph, double ordinal,
|
|
286
|
+
double threadSlot, const MemoryView& wakes) {
|
|
287
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
288
|
+
narsil_remove_request request{};
|
|
289
|
+
request.ordinal = signedOf(ordinal, "The ordinal");
|
|
290
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
291
|
+
attachedGraph->wakes.count = 0;
|
|
292
|
+
narsil_status status = narsil_remove(&attachedGraph->graph, &request);
|
|
293
|
+
handOverWakes(attachedGraph->wakes, wakes);
|
|
294
|
+
return statusOf(status);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
double HybridNarsilCoreImpl::compact(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
298
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
299
|
+
double threadSlot, const MemoryView& wakes) {
|
|
300
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
301
|
+
auto attachedStore = attachedStoreOf(store);
|
|
302
|
+
narsil_compact_request request{};
|
|
303
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
304
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
305
|
+
attachedGraph->wakes.count = 0;
|
|
306
|
+
narsil_status status = narsil_compact(workspace(), &attachedGraph->graph, &attachedStore->store, &request);
|
|
307
|
+
handOverWakes(attachedGraph->wakes, wakes);
|
|
308
|
+
return statusOf(status);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
double HybridNarsilCoreImpl::connectUnreached(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
312
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store,
|
|
313
|
+
double metric, const MemoryView& nearby, double threadSlot,
|
|
314
|
+
const MemoryView& wakes) {
|
|
315
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
316
|
+
auto attachedStore = attachedStoreOf(store);
|
|
317
|
+
narsil_connect_request request{};
|
|
318
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
319
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
320
|
+
size_t nearbyCount = 0;
|
|
321
|
+
request.nearby = elementsOf<int32_t>(nearby, 0, "The nearby ordinals", &nearbyCount);
|
|
322
|
+
request.nearby_count = clampedCount(nearbyCount);
|
|
323
|
+
attachedGraph->wakes.count = 0;
|
|
324
|
+
narsil_status status =
|
|
325
|
+
narsil_connect_unreached(workspace(), &attachedGraph->graph, &attachedStore->store, &request);
|
|
326
|
+
handOverWakes(attachedGraph->wakes, wakes);
|
|
327
|
+
return statusOf(status);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
std::shared_ptr<Promise<NativeConnectOutcome>> HybridNarsilCoreImpl::connectUnreachedAsync(
|
|
331
|
+
const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
332
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric, const MemoryView& nearby,
|
|
333
|
+
double threadSlot) {
|
|
334
|
+
auto attachedGraph = attachedGraphOf(graph);
|
|
335
|
+
auto attachedStore = attachedStoreOf(store);
|
|
336
|
+
narsil_connect_request request{};
|
|
337
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
338
|
+
request.thread_slot = unsignedOf(threadSlot, "The thread slot");
|
|
339
|
+
if (request.thread_slot >= attachedGraph->graph.thread_slots) throwInvalid("The thread slot is out of range");
|
|
340
|
+
size_t nearbyCount = 0;
|
|
341
|
+
const int32_t* chosen = elementsOf<int32_t>(nearby, 0, "The nearby ordinals", &nearbyCount);
|
|
342
|
+
auto nearbyOrdinals = std::make_shared<std::vector<int32_t>>(chosen, chosen + nearbyCount);
|
|
343
|
+
auto held = std::make_shared<GraphHeldAlone>(attachedGraph->graph.header);
|
|
344
|
+
if (!held->held()) {
|
|
345
|
+
return Promise<NativeConnectOutcome>::resolved(
|
|
346
|
+
NativeConnectOutcome(statusOf(NARSIL_GRAPH_NOT_HELD_ALONE), allocatedFor(1, sizeof(int32_t))));
|
|
347
|
+
}
|
|
348
|
+
auto use = startBackgroundUse(shared_cast<HybridNarsilCoreImpl>(), attachedStore, request.thread_slot);
|
|
349
|
+
narsil_graph walked = attachedGraph->graph;
|
|
350
|
+
return Promise<NativeConnectOutcome>::async([use, held, attachedGraph, attachedStore, request, nearbyOrdinals,
|
|
351
|
+
walked]() mutable {
|
|
352
|
+
ReleaseWhenDone done(use);
|
|
353
|
+
auto wakes = std::make_shared<PendingWakes>();
|
|
354
|
+
walked.wake_context = wakes.get();
|
|
355
|
+
request.nearby = nearbyOrdinals->empty() ? nullptr : nearbyOrdinals->data();
|
|
356
|
+
request.nearby_count = clampedCount(nearbyOrdinals->size());
|
|
357
|
+
narsil_status status = narsil_connect_unreached(use->workspace, &walked, &attachedStore->store, &request);
|
|
358
|
+
if (status == NARSIL_OK) held->markEveryNodeLinked();
|
|
359
|
+
held->release();
|
|
360
|
+
auto list = allocatedFor(1 + static_cast<size_t>(wakes->count), sizeof(int32_t));
|
|
361
|
+
auto* words = reinterpret_cast<int32_t*>(list->data());
|
|
362
|
+
words[0] = static_cast<int32_t>(wakes->count);
|
|
363
|
+
for (uint32_t i = 0; i < wakes->count; i++) words[1 + i] = wakes->ordinals[i];
|
|
364
|
+
return NativeConnectOutcome(statusOf(status), list);
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
double HybridNarsilCoreImpl::measure(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
369
|
+
const MemoryView& ordinals, double count, const MemoryView& totals) {
|
|
370
|
+
auto attachedStore = attachedStoreOf(store);
|
|
371
|
+
narsil_ordinals_request request{};
|
|
372
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
373
|
+
request.count = unsignedOf(count, "The count");
|
|
374
|
+
request.ordinals = elementsOf<int32_t>(ordinals, request.count == 0 ? 1 : request.count, "The ordinals");
|
|
375
|
+
size_t needed = static_cast<size_t>(attachedStore->store.dimension) + MEASURE_TOTALS_PAST_DIMENSION;
|
|
376
|
+
double* out = elementsOf<double>(totals, needed, "The totals");
|
|
377
|
+
return statusOf(narsil_measure(workspace(), &attachedStore->store, &request, out));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
double HybridNarsilCoreImpl::quantise(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
381
|
+
const MemoryView& ordinals, double count) {
|
|
382
|
+
auto attachedStore = attachedStoreOf(store);
|
|
383
|
+
narsil_ordinals_request request{};
|
|
384
|
+
request.metric = unsignedOf(metric, "The metric");
|
|
385
|
+
request.count = unsignedOf(count, "The count");
|
|
386
|
+
request.ordinals = elementsOf<int32_t>(ordinals, request.count == 0 ? 1 : request.count, "The ordinals");
|
|
387
|
+
return statusOf(narsil_quantise(workspace(), &attachedStore->store, &request));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "HybridNarsilCoreSpec.hpp"
|
|
4
|
+
#include "narsil_core.h"
|
|
5
|
+
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <mutex>
|
|
8
|
+
#include <unordered_map>
|
|
9
|
+
#include <unordered_set>
|
|
10
|
+
|
|
11
|
+
namespace margelo::nitro::narsil {
|
|
12
|
+
|
|
13
|
+
class HybridNarsilCoreImpl : public HybridNarsilCoreSpec {
|
|
14
|
+
public:
|
|
15
|
+
HybridNarsilCoreImpl() : HybridObject(TAG) {}
|
|
16
|
+
~HybridNarsilCoreImpl() override;
|
|
17
|
+
|
|
18
|
+
double abiVersion() override;
|
|
19
|
+
double workspaceBytes() override;
|
|
20
|
+
std::shared_ptr<HybridNarsilAttachedGraphSpec> attachGraph(const GraphMemory& memory) override;
|
|
21
|
+
std::shared_ptr<HybridNarsilAttachedStoreSpec> attachStore(const StoreMemory& memory) override;
|
|
22
|
+
double search(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
23
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, const MemoryView& query, double metric,
|
|
24
|
+
double candidateCount, double threadSlot, const MemoryView& ordinals, const MemoryView& distances,
|
|
25
|
+
const MemoryView& accepted, bool filtered) override;
|
|
26
|
+
double score(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, const MemoryView& query, double metric,
|
|
27
|
+
const MemoryView& ordinals, double count, const MemoryView& distances) override;
|
|
28
|
+
std::shared_ptr<Promise<NativeSearchHits>> searchAsync(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
29
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store,
|
|
30
|
+
const MemoryView& query, double metric,
|
|
31
|
+
double candidateCount, double threadSlot,
|
|
32
|
+
const MemoryView& accepted, bool filtered) override;
|
|
33
|
+
std::shared_ptr<Promise<NativeScores>> scoreAsync(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store,
|
|
34
|
+
const MemoryView& query, double metric,
|
|
35
|
+
const MemoryView& ordinals, double count,
|
|
36
|
+
double threadSlot) override;
|
|
37
|
+
double place(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
38
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric, double ordinal,
|
|
39
|
+
double topLayer, double graphHeldAlone, double threadSlot, const MemoryView& wakes) override;
|
|
40
|
+
double remove(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph, double ordinal, double threadSlot,
|
|
41
|
+
const MemoryView& wakes) override;
|
|
42
|
+
double compact(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
43
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric, double threadSlot,
|
|
44
|
+
const MemoryView& wakes) override;
|
|
45
|
+
double connectUnreached(const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
46
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
47
|
+
const MemoryView& nearby, double threadSlot, const MemoryView& wakes) override;
|
|
48
|
+
std::shared_ptr<Promise<NativeConnectOutcome>> connectUnreachedAsync(
|
|
49
|
+
const std::shared_ptr<HybridNarsilAttachedGraphSpec>& graph,
|
|
50
|
+
const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric, const MemoryView& nearby,
|
|
51
|
+
double threadSlot) override;
|
|
52
|
+
double measure(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
53
|
+
const MemoryView& ordinals, double count, const MemoryView& totals) override;
|
|
54
|
+
double quantise(const std::shared_ptr<HybridNarsilAttachedStoreSpec>& store, double metric,
|
|
55
|
+
const MemoryView& ordinals, double count) override;
|
|
56
|
+
|
|
57
|
+
narsil_workspace* claimBackgroundSlot(uint32_t threadSlot);
|
|
58
|
+
void releaseBackgroundSlot(uint32_t threadSlot);
|
|
59
|
+
|
|
60
|
+
private:
|
|
61
|
+
narsil_workspace* workspace();
|
|
62
|
+
narsil_workspace* _workspace = nullptr;
|
|
63
|
+
std::mutex _backgroundLock;
|
|
64
|
+
std::unordered_map<uint32_t, narsil_workspace*> _backgroundWorkspaces;
|
|
65
|
+
std::unordered_set<uint32_t> _busyBackgroundSlots;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
}
|