usearch 2.2.1 → 2.3.1
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/.github/workflows/release.yml +2 -1
- package/.releaserc +6 -2
- package/CITATION.cff +1 -1
- package/Cargo.toml +1 -1
- package/README.md +1 -1
- package/conanfile.py +1 -1
- package/cpp/bench.cpp +1 -0
- package/csharp/nuget/nuget-package.props +1 -1
- package/include/usearch/index.hpp +51 -15
- package/include/usearch/index_dense.hpp +43 -20
- package/include/usearch/index_plugins.hpp +9 -1
- package/package.json +1 -1
- package/python/lib.cpp +135 -63
- package/python/usearch/index.py +112 -79
- package/rust/README.md +17 -18
- package/swift/README.md +11 -7
- package/wasmer.toml +1 -1
|
@@ -219,7 +219,7 @@ jobs:
|
|
|
219
219
|
publish_hashes:
|
|
220
220
|
name: Add hashes to release notes
|
|
221
221
|
runs-on: ubuntu-latest
|
|
222
|
-
needs: [versioning, create_linux_deb_package, create_windows_dll_library, create_macos_library]
|
|
222
|
+
needs: [versioning, create_linux_deb_package, create_windows_dll_library, create_macos_library, deploy_docs_pages]
|
|
223
223
|
steps:
|
|
224
224
|
- name: Get last release ID
|
|
225
225
|
id: last_release
|
|
@@ -266,6 +266,7 @@ jobs:
|
|
|
266
266
|
* ${{ steps.hashes.outputs.asset_name_6 }} : `${{ steps.hashes.outputs.asset_hash_6 }}`
|
|
267
267
|
* ${{ steps.hashes.outputs.asset_name_7 }} : `${{ steps.hashes.outputs.asset_hash_7 }}`
|
|
268
268
|
* ${{ steps.hashes.outputs.asset_name_8 }} : `${{ steps.hashes.outputs.asset_hash_8 }}`
|
|
269
|
+
* ${{ steps.hashes.outputs.asset_name_9 }} : `${{ steps.hashes.outputs.asset_hash_9 }}`
|
|
269
270
|
|
|
270
271
|
|
|
271
272
|
build_wheels:
|
package/.releaserc
CHANGED
|
@@ -77,10 +77,14 @@
|
|
|
77
77
|
"conanfile.py",
|
|
78
78
|
"package.json",
|
|
79
79
|
"Cargo.toml",
|
|
80
|
-
"wasmer.toml"
|
|
80
|
+
"wasmer.toml",
|
|
81
|
+
"./include/usearch/index.hpp",
|
|
82
|
+
"README.md",
|
|
83
|
+
"./csharp/nuget/nuget-package.props",
|
|
84
|
+
"CITATION.cff"
|
|
81
85
|
],
|
|
82
86
|
"message": "Build: Released ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
83
87
|
}
|
|
84
88
|
]
|
|
85
89
|
]
|
|
86
|
-
}
|
|
90
|
+
}
|
package/CITATION.cff
CHANGED
package/Cargo.toml
CHANGED
package/README.md
CHANGED
package/conanfile.py
CHANGED
|
@@ -4,7 +4,7 @@ from conans import ConanFile
|
|
|
4
4
|
class USearchConan(ConanFile):
|
|
5
5
|
|
|
6
6
|
name = 'USearch'
|
|
7
|
-
version = '2.
|
|
7
|
+
version = '2.3.1'
|
|
8
8
|
license = 'Apache 2.0'
|
|
9
9
|
url = 'https://github.com/unum-cloud/usearch'
|
|
10
10
|
description = 'Smaller & Faster Single-File Vector Search Engine from Unum'
|
package/cpp/bench.cpp
CHANGED
|
@@ -372,6 +372,7 @@ static void single_shot(dataset_at& dataset, index_at& index, bool construct = t
|
|
|
372
372
|
executor, [&](std::size_t progress, std::size_t total) {
|
|
373
373
|
if (progress % 1000 == 0)
|
|
374
374
|
printer.print(progress, total);
|
|
375
|
+
return true;
|
|
375
376
|
});
|
|
376
377
|
join_attempts = result.visited_members;
|
|
377
378
|
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
#ifndef UNUM_USEARCH_HPP
|
|
10
10
|
#define UNUM_USEARCH_HPP
|
|
11
11
|
|
|
12
|
-
#define USEARCH_VERSION_MAJOR
|
|
13
|
-
#define USEARCH_VERSION_MINOR
|
|
14
|
-
#define USEARCH_VERSION_PATCH
|
|
12
|
+
#define USEARCH_VERSION_MAJOR 2
|
|
13
|
+
#define USEARCH_VERSION_MINOR 3
|
|
14
|
+
#define USEARCH_VERSION_PATCH 1
|
|
15
15
|
|
|
16
16
|
// Inferring C++ version
|
|
17
17
|
// https://stackoverflow.com/a/61552074
|
|
@@ -1212,9 +1212,10 @@ struct dummy_callback_t {
|
|
|
1212
1212
|
*
|
|
1213
1213
|
* This is particularly helpful when handling long-running tasks, like serialization,
|
|
1214
1214
|
* saving, and loading from disk, or index-level joins.
|
|
1215
|
+
* The reporter checks return value to continue or stop the process, `false` means need to stop.
|
|
1215
1216
|
*/
|
|
1216
1217
|
struct dummy_progress_t {
|
|
1217
|
-
inline
|
|
1218
|
+
inline bool operator()(std::size_t /*processed*/, std::size_t /*total*/) const noexcept { return true; }
|
|
1218
1219
|
};
|
|
1219
1220
|
|
|
1220
1221
|
/**
|
|
@@ -2690,6 +2691,10 @@ class index_gt {
|
|
|
2690
2691
|
if (!output(&header, sizeof(header)))
|
|
2691
2692
|
return result.failed("Failed to serialize the header into stream");
|
|
2692
2693
|
|
|
2694
|
+
// Progress status
|
|
2695
|
+
std::size_t processed = 0;
|
|
2696
|
+
std::size_t const total = 2 * header.size;
|
|
2697
|
+
|
|
2693
2698
|
// Export the number of levels per node
|
|
2694
2699
|
// That is both enough to estimate the overall memory consumption,
|
|
2695
2700
|
// and to be able to estimate the offsets of every entry in the file.
|
|
@@ -2697,15 +2702,18 @@ class index_gt {
|
|
|
2697
2702
|
node_t node = node_at_(i);
|
|
2698
2703
|
level_t level = node.level();
|
|
2699
2704
|
if (!output(&level, sizeof(level)))
|
|
2700
|
-
return result.failed("Failed to serialize
|
|
2705
|
+
return result.failed("Failed to serialize into stream");
|
|
2706
|
+
if (!progress(++processed, total))
|
|
2707
|
+
return result.failed("Terminated by user");
|
|
2701
2708
|
}
|
|
2702
2709
|
|
|
2703
2710
|
// After that dump the nodes themselves
|
|
2704
2711
|
for (std::size_t i = 0; i != header.size; ++i) {
|
|
2705
2712
|
span_bytes_t node_bytes = node_bytes_(node_at_(i));
|
|
2706
2713
|
if (!output(node_bytes.data(), node_bytes.size()))
|
|
2707
|
-
return result.failed("Failed to serialize
|
|
2708
|
-
progress(
|
|
2714
|
+
return result.failed("Failed to serialize into stream");
|
|
2715
|
+
if (!progress(++processed, total))
|
|
2716
|
+
return result.failed("Terminated by user");
|
|
2709
2717
|
}
|
|
2710
2718
|
|
|
2711
2719
|
return {};
|
|
@@ -2763,7 +2771,8 @@ class index_gt {
|
|
|
2763
2771
|
return result.failed("Failed to pull nodes from the stream");
|
|
2764
2772
|
}
|
|
2765
2773
|
nodes_[i] = node_t{node_bytes.data()};
|
|
2766
|
-
progress(i, header.size)
|
|
2774
|
+
if (!progress(i + 1, header.size))
|
|
2775
|
+
return result.failed("Terminated by user");
|
|
2767
2776
|
}
|
|
2768
2777
|
return {};
|
|
2769
2778
|
}
|
|
@@ -2936,7 +2945,8 @@ class index_gt {
|
|
|
2936
2945
|
// Rapidly address all the nodes
|
|
2937
2946
|
for (std::size_t i = 0; i != header.size; ++i) {
|
|
2938
2947
|
nodes_[i] = node_t{(byte_t*)file.data() + offsets[i]};
|
|
2939
|
-
progress(i, header.size)
|
|
2948
|
+
if (!progress(i + 1, header.size))
|
|
2949
|
+
return result.failed("Terminated by user");
|
|
2940
2950
|
}
|
|
2941
2951
|
viewed_file_ = std::move(file);
|
|
2942
2952
|
return {};
|
|
@@ -2986,8 +2996,13 @@ class index_gt {
|
|
|
2986
2996
|
using slot_level_allocator_t = typename dynamic_allocator_traits_t::template rebind_alloc<slot_level_t>;
|
|
2987
2997
|
buffer_gt<slot_level_t, slot_level_allocator_t> slots_and_levels(size());
|
|
2988
2998
|
|
|
2999
|
+
// Progress status
|
|
3000
|
+
std::atomic<bool> do_tasks{true};
|
|
3001
|
+
std::atomic<std::size_t> processed{0};
|
|
3002
|
+
std::size_t const total = 3 * slots_and_levels.size();
|
|
3003
|
+
|
|
2989
3004
|
// For every bottom level node, determine its parent cluster
|
|
2990
|
-
executor.
|
|
3005
|
+
executor.dynamic(slots_and_levels.size(), [&](std::size_t thread_idx, std::size_t old_slot) {
|
|
2991
3006
|
context_t& context = contexts_[thread_idx];
|
|
2992
3007
|
std::size_t cluster = search_for_one_( //
|
|
2993
3008
|
values[citerator_at(old_slot)], //
|
|
@@ -2997,7 +3012,13 @@ class index_gt {
|
|
|
2997
3012
|
static_cast<compressed_slot_t>(old_slot), //
|
|
2998
3013
|
static_cast<compressed_slot_t>(cluster), //
|
|
2999
3014
|
node_at_(old_slot).level()};
|
|
3015
|
+
++processed;
|
|
3016
|
+
if (thread_idx == 0)
|
|
3017
|
+
do_tasks = progress(processed.load(), total);
|
|
3018
|
+
return do_tasks.load();
|
|
3000
3019
|
});
|
|
3020
|
+
if (!do_tasks.load())
|
|
3021
|
+
return;
|
|
3001
3022
|
|
|
3002
3023
|
// Where the actual permutation happens:
|
|
3003
3024
|
std::sort(slots_and_levels.begin(), slots_and_levels.end(), [](slot_level_t const& a, slot_level_t const& b) {
|
|
@@ -3027,8 +3048,8 @@ class index_gt {
|
|
|
3027
3048
|
neighbor = static_cast<compressed_slot_t>(old_slot_to_new[compressed_slot_t(neighbor)]);
|
|
3028
3049
|
|
|
3029
3050
|
reordered_nodes[new_slot] = new_node;
|
|
3030
|
-
|
|
3031
|
-
|
|
3051
|
+
if (!progress(++processed, total))
|
|
3052
|
+
return;
|
|
3032
3053
|
}
|
|
3033
3054
|
|
|
3034
3055
|
for (std::size_t new_slot = 0; new_slot != slots_and_levels.size(); ++new_slot) {
|
|
@@ -3036,6 +3057,8 @@ class index_gt {
|
|
|
3036
3057
|
slot_transition(node_at_(old_slot).ckey(), //
|
|
3037
3058
|
static_cast<compressed_slot_t>(old_slot), //
|
|
3038
3059
|
static_cast<compressed_slot_t>(new_slot));
|
|
3060
|
+
if (!progress(++processed, total))
|
|
3061
|
+
return;
|
|
3039
3062
|
}
|
|
3040
3063
|
|
|
3041
3064
|
nodes_ = std::move(reordered_nodes);
|
|
@@ -3064,9 +3087,13 @@ class index_gt {
|
|
|
3064
3087
|
executor_at&& executor = executor_at{}, //
|
|
3065
3088
|
progress_at&& progress = progress_at{}) noexcept {
|
|
3066
3089
|
|
|
3090
|
+
// Progress status
|
|
3091
|
+
std::atomic<bool> do_tasks{true};
|
|
3092
|
+
std::atomic<std::size_t> processed{0};
|
|
3093
|
+
|
|
3067
3094
|
// Erase all the incoming links
|
|
3068
3095
|
std::size_t nodes_count = size();
|
|
3069
|
-
executor.
|
|
3096
|
+
executor.dynamic(nodes_count, [&](std::size_t thread_idx, std::size_t node_idx) {
|
|
3070
3097
|
node_t node = node_at_(node_idx);
|
|
3071
3098
|
for (level_t level = 0; level <= node.level(); ++level) {
|
|
3072
3099
|
neighbors_ref_t neighbors = neighbors_(node, level);
|
|
@@ -3079,8 +3106,14 @@ class index_gt {
|
|
|
3079
3106
|
neighbors.push_back(neighbor_slot);
|
|
3080
3107
|
}
|
|
3081
3108
|
}
|
|
3082
|
-
|
|
3109
|
+
++processed;
|
|
3110
|
+
if (thread_idx == 0)
|
|
3111
|
+
do_tasks = progress(processed.load(), nodes_count);
|
|
3112
|
+
return do_tasks.load();
|
|
3083
3113
|
});
|
|
3114
|
+
|
|
3115
|
+
// At the end report the latest numbers, because the reporter thread may be finished earlier
|
|
3116
|
+
progress(processed.load(), nodes_count);
|
|
3084
3117
|
}
|
|
3085
3118
|
|
|
3086
3119
|
private:
|
|
@@ -3710,7 +3743,10 @@ static join_result_t join( //
|
|
|
3710
3743
|
passed_rounds = ++rounds;
|
|
3711
3744
|
total_rounds = passed_rounds + free_men.size();
|
|
3712
3745
|
}
|
|
3713
|
-
progress(passed_rounds, total_rounds)
|
|
3746
|
+
if (thread_idx == 0 && !progress(passed_rounds, total_rounds)) {
|
|
3747
|
+
atomic_error.store("Terminated by user");
|
|
3748
|
+
break;
|
|
3749
|
+
}
|
|
3714
3750
|
while (men_locks.atomic_set(free_man_slot))
|
|
3715
3751
|
;
|
|
3716
3752
|
|
|
@@ -767,7 +767,9 @@ class index_dense_gt {
|
|
|
767
767
|
* @brief Saves serialized binary index representation to a stream.
|
|
768
768
|
*/
|
|
769
769
|
template <typename output_callback_at, typename progress_at = dummy_progress_t>
|
|
770
|
-
serialization_result_t save_to_stream(output_callback_at&& output,
|
|
770
|
+
serialization_result_t save_to_stream(output_callback_at&& output, //
|
|
771
|
+
serialization_config_t config = {}, //
|
|
772
|
+
progress_at&& progress = {}) const {
|
|
771
773
|
|
|
772
774
|
serialization_result_t result;
|
|
773
775
|
std::uint64_t matrix_rows = 0;
|
|
@@ -831,7 +833,7 @@ class index_dense_gt {
|
|
|
831
833
|
}
|
|
832
834
|
|
|
833
835
|
// Save the actual proximity graph
|
|
834
|
-
return typed_->save_to_stream(std::forward<output_callback_at>(output));
|
|
836
|
+
return typed_->save_to_stream(std::forward<output_callback_at>(output), std::forward<progress_at>(progress));
|
|
835
837
|
}
|
|
836
838
|
|
|
837
839
|
/**
|
|
@@ -853,8 +855,10 @@ class index_dense_gt {
|
|
|
853
855
|
* @param[in] config Configuration parameters for imports.
|
|
854
856
|
* @return Outcome descriptor explicitly convertible to boolean.
|
|
855
857
|
*/
|
|
856
|
-
template <typename input_callback_at>
|
|
857
|
-
serialization_result_t load_from_stream(input_callback_at&& input,
|
|
858
|
+
template <typename input_callback_at, typename progress_at = dummy_progress_t>
|
|
859
|
+
serialization_result_t load_from_stream(input_callback_at&& input, //
|
|
860
|
+
serialization_config_t config = {}, //
|
|
861
|
+
progress_at&& progress = {}) {
|
|
858
862
|
|
|
859
863
|
// Discard all previous memory allocations of `vectors_tape_allocator_`
|
|
860
864
|
reset();
|
|
@@ -915,7 +919,7 @@ class index_dense_gt {
|
|
|
915
919
|
}
|
|
916
920
|
|
|
917
921
|
// Pull the actual proximity graph
|
|
918
|
-
result = typed_->load_from_stream(std::forward<input_callback_at>(input));
|
|
922
|
+
result = typed_->load_from_stream(std::forward<input_callback_at>(input), std::forward<progress_at>(progress));
|
|
919
923
|
if (!result)
|
|
920
924
|
return result;
|
|
921
925
|
if (typed_->size() != static_cast<std::size_t>(matrix_rows))
|
|
@@ -931,7 +935,10 @@ class index_dense_gt {
|
|
|
931
935
|
* @param[in] config Configuration parameters for imports.
|
|
932
936
|
* @return Outcome descriptor explicitly convertible to boolean.
|
|
933
937
|
*/
|
|
934
|
-
|
|
938
|
+
template <typename progress_at = dummy_progress_t>
|
|
939
|
+
serialization_result_t view(memory_mapped_file_t file, //
|
|
940
|
+
std::size_t offset = 0, serialization_config_t config = {}, //
|
|
941
|
+
progress_at&& progress = {}) {
|
|
935
942
|
|
|
936
943
|
// Discard all previous memory allocations of `vectors_tape_allocator_`
|
|
937
944
|
reset();
|
|
@@ -997,7 +1004,7 @@ class index_dense_gt {
|
|
|
997
1004
|
}
|
|
998
1005
|
|
|
999
1006
|
// Pull the actual proximity graph
|
|
1000
|
-
result = typed_->view(std::move(file), offset);
|
|
1007
|
+
result = typed_->view(std::move(file), offset, std::forward<progress_at>(progress));
|
|
1001
1008
|
if (!result)
|
|
1002
1009
|
return result;
|
|
1003
1010
|
if (typed_->size() != static_cast<std::size_t>(matrix_rows))
|
|
@@ -1019,7 +1026,9 @@ class index_dense_gt {
|
|
|
1019
1026
|
* @param[in] config Configuration parameters for exports.
|
|
1020
1027
|
* @return Outcome descriptor explicitly convertible to boolean.
|
|
1021
1028
|
*/
|
|
1022
|
-
|
|
1029
|
+
template <typename progress_at = dummy_progress_t>
|
|
1030
|
+
serialization_result_t save(output_file_t file, serialization_config_t config = {},
|
|
1031
|
+
progress_at&& progress = {}) const {
|
|
1023
1032
|
|
|
1024
1033
|
serialization_result_t io_result = file.open_if_not();
|
|
1025
1034
|
if (!io_result)
|
|
@@ -1030,7 +1039,7 @@ class index_dense_gt {
|
|
|
1030
1039
|
io_result = file.write(buffer, length);
|
|
1031
1040
|
return !!io_result;
|
|
1032
1041
|
},
|
|
1033
|
-
config);
|
|
1042
|
+
config, std::forward<progress_at>(progress));
|
|
1034
1043
|
|
|
1035
1044
|
if (!stream_result)
|
|
1036
1045
|
return stream_result;
|
|
@@ -1041,8 +1050,11 @@ class index_dense_gt {
|
|
|
1041
1050
|
* @brief Memory-maps the serialized binary index representation from disk,
|
|
1042
1051
|
* @b without copying data into RAM, and fetching it on-demand.
|
|
1043
1052
|
*/
|
|
1044
|
-
|
|
1045
|
-
|
|
1053
|
+
template <typename progress_at = dummy_progress_t>
|
|
1054
|
+
serialization_result_t save(memory_mapped_file_t file, //
|
|
1055
|
+
std::size_t offset = 0, //
|
|
1056
|
+
serialization_config_t config = {}, //
|
|
1057
|
+
progress_at&& progress = {}) const {
|
|
1046
1058
|
|
|
1047
1059
|
serialization_result_t io_result = file.open_if_not();
|
|
1048
1060
|
if (!io_result)
|
|
@@ -1056,7 +1068,7 @@ class index_dense_gt {
|
|
|
1056
1068
|
offset += length;
|
|
1057
1069
|
return true;
|
|
1058
1070
|
},
|
|
1059
|
-
config);
|
|
1071
|
+
config, std::forward<progress_at>(progress));
|
|
1060
1072
|
|
|
1061
1073
|
return stream_result;
|
|
1062
1074
|
}
|
|
@@ -1067,7 +1079,8 @@ class index_dense_gt {
|
|
|
1067
1079
|
* @param[in] config Configuration parameters for imports.
|
|
1068
1080
|
* @return Outcome descriptor explicitly convertible to boolean.
|
|
1069
1081
|
*/
|
|
1070
|
-
|
|
1082
|
+
template <typename progress_at = dummy_progress_t>
|
|
1083
|
+
serialization_result_t load(input_file_t file, serialization_config_t config = {}, progress_at&& progress = {}) {
|
|
1071
1084
|
|
|
1072
1085
|
serialization_result_t io_result = file.open_if_not();
|
|
1073
1086
|
if (!io_result)
|
|
@@ -1078,7 +1091,7 @@ class index_dense_gt {
|
|
|
1078
1091
|
io_result = file.read(buffer, length);
|
|
1079
1092
|
return !!io_result;
|
|
1080
1093
|
},
|
|
1081
|
-
config);
|
|
1094
|
+
config, std::forward<progress_at>(progress));
|
|
1082
1095
|
|
|
1083
1096
|
if (!stream_result)
|
|
1084
1097
|
return stream_result;
|
|
@@ -1089,7 +1102,11 @@ class index_dense_gt {
|
|
|
1089
1102
|
* @brief Memory-maps the serialized binary index representation from disk,
|
|
1090
1103
|
* @b without copying data into RAM, and fetching it on-demand.
|
|
1091
1104
|
*/
|
|
1092
|
-
|
|
1105
|
+
template <typename progress_at = dummy_progress_t>
|
|
1106
|
+
serialization_result_t load(memory_mapped_file_t file, //
|
|
1107
|
+
std::size_t offset = 0, //
|
|
1108
|
+
serialization_config_t config = {}, //
|
|
1109
|
+
progress_at&& progress = {}) {
|
|
1093
1110
|
|
|
1094
1111
|
serialization_result_t io_result = file.open_if_not();
|
|
1095
1112
|
if (!io_result)
|
|
@@ -1103,17 +1120,23 @@ class index_dense_gt {
|
|
|
1103
1120
|
offset += length;
|
|
1104
1121
|
return true;
|
|
1105
1122
|
},
|
|
1106
|
-
config);
|
|
1123
|
+
config, std::forward<progress_at>(progress));
|
|
1107
1124
|
|
|
1108
1125
|
return stream_result;
|
|
1109
1126
|
}
|
|
1110
1127
|
|
|
1111
|
-
|
|
1112
|
-
|
|
1128
|
+
template <typename progress_at = dummy_progress_t>
|
|
1129
|
+
serialization_result_t save(char const* file_path, //
|
|
1130
|
+
serialization_config_t config = {}, //
|
|
1131
|
+
progress_at&& progress = {}) const {
|
|
1132
|
+
return save(output_file_t(file_path), config, std::forward<progress_at>(progress));
|
|
1113
1133
|
}
|
|
1114
1134
|
|
|
1115
|
-
|
|
1116
|
-
|
|
1135
|
+
template <typename progress_at = dummy_progress_t>
|
|
1136
|
+
serialization_result_t load(char const* file_path, //
|
|
1137
|
+
serialization_config_t config = {}, //
|
|
1138
|
+
progress_at&& progress = {}) {
|
|
1139
|
+
return load(input_file_t(file_path), config, std::forward<progress_at>(progress));
|
|
1117
1140
|
}
|
|
1118
1141
|
|
|
1119
1142
|
/**
|
|
@@ -41,7 +41,15 @@
|
|
|
41
41
|
#endif
|
|
42
42
|
|
|
43
43
|
#if USEARCH_USE_SIMSIMD
|
|
44
|
-
#if
|
|
44
|
+
#if defined(USEARCH_DEFINED_LINUX)
|
|
45
|
+
#define SIMSIMD_TARGET_X86_AVX2 1
|
|
46
|
+
#define SIMSIMD_TARGET_X86_AVX512 1
|
|
47
|
+
#define SIMSIMD_TARGET_ARM_NEON 1
|
|
48
|
+
#define SIMSIMD_TARGET_ARM_SVE 1
|
|
49
|
+
#include <simsimd/simsimd.h>
|
|
50
|
+
#elif defined(USEARCH_DEFINED_APPLE)
|
|
51
|
+
#define SIMSIMD_TARGET_X86_AVX2 1
|
|
52
|
+
#define SIMSIMD_TARGET_ARM_NEON 1
|
|
45
53
|
#include <simsimd/simsimd.h>
|
|
46
54
|
#endif
|
|
47
55
|
#endif
|