usearch 0.10.0 → 0.11.0

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.
Files changed (41) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/.gitmodules +3 -0
  3. package/.vscode/settings.json +2 -0
  4. package/Cargo.toml +1 -1
  5. package/Package.swift +1 -0
  6. package/README.md +1 -1
  7. package/VERSION +1 -1
  8. package/binding.gyp +4 -3
  9. package/build.gradle +1 -1
  10. package/build.rs +1 -0
  11. package/conanfile.py +1 -1
  12. package/docs/compilation.md +6 -3
  13. package/include/usearch/usearch.hpp +133 -43
  14. package/package.json +1 -1
  15. package/python/lib.cpp +36 -24
  16. package/python/scripts/bench.py +2 -2
  17. package/python/scripts/test.py +1 -1
  18. package/python/usearch/index.py +298 -0
  19. package/robin-map/.codecov.yml +5 -0
  20. package/robin-map/.github/workflows/ci.yml +136 -0
  21. package/robin-map/CMakeLists.txt +86 -0
  22. package/robin-map/LICENSE +21 -0
  23. package/robin-map/README.md +483 -0
  24. package/robin-map/cmake/tsl-robin-mapConfig.cmake.in +9 -0
  25. package/robin-map/doxygen.conf +2483 -0
  26. package/robin-map/include/tsl/robin_growth_policy.h +406 -0
  27. package/robin-map/include/tsl/robin_hash.h +1639 -0
  28. package/robin-map/include/tsl/robin_map.h +807 -0
  29. package/robin-map/include/tsl/robin_set.h +660 -0
  30. package/robin-map/tests/CMakeLists.txt +26 -0
  31. package/robin-map/tests/custom_allocator_tests.cpp +138 -0
  32. package/robin-map/tests/main.cpp +26 -0
  33. package/robin-map/tests/policy_tests.cpp +97 -0
  34. package/robin-map/tests/robin_map_tests.cpp +1451 -0
  35. package/robin-map/tests/robin_set_tests.cpp +164 -0
  36. package/robin-map/tests/utils.h +443 -0
  37. package/robin-map/tsl-robin-map.natvis +78 -0
  38. package/setup.py +4 -2
  39. package/src/CMakeLists.txt +1 -0
  40. package/src/punned.hpp +50 -6
  41. package/src/test.cpp +29 -8
@@ -231,7 +231,7 @@ jobs:
231
231
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
232
232
  with:
233
233
  file: docs.tar.gz
234
- asset_name: docs.tar.gz
234
+ update_latest_release: true
235
235
 
236
236
  deploy_docs_pages:
237
237
  name: Deploy GitHub Pages
package/.gitmodules CHANGED
@@ -4,3 +4,6 @@
4
4
  [submodule "fp16"]
5
5
  path = fp16
6
6
  url = https://github.com/maratyszcza/fp16
7
+ [submodule "robin-map"]
8
+ path = robin-map
9
+ url = https://github.com/tessil/robin-map
@@ -125,10 +125,12 @@
125
125
  "OPENMP",
126
126
  "preprocess",
127
127
  "Quickstart",
128
+ "rtype",
128
129
  "simsimd",
129
130
  "SLOC",
130
131
  "usearch",
131
132
  "usecases"
132
133
  ],
134
+ "autoDocstring.docstringFormat": "sphinx",
133
135
  "java.configuration.updateBuildConfiguration": "interactive"
134
136
  }
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "usearch"
3
- version = "0.10.0"
3
+ version = "0.11.0"
4
4
  authors = ["Ashot Vardanian <1983160+ashvardanian@users.noreply.github.com>"]
5
5
  description = "Smaller & Faster Single-File Vector Search Engine from Unum"
6
6
  edition = "2021"
package/Package.swift CHANGED
@@ -20,6 +20,7 @@ let package = Package(
20
20
  .headerSearchPath("../include/"),
21
21
  .headerSearchPath("../src/"),
22
22
  .headerSearchPath("../fp16/include/"),
23
+ .headerSearchPath("../robin-map/include/"),
23
24
  .headerSearchPath("../simismd/include/")
24
25
  ]
25
26
  ),
package/README.md CHANGED
@@ -308,7 +308,7 @@ def python_dot(a, b, n, m):
308
308
  c += a_array[i] * b_array[i]
309
309
  return c
310
310
 
311
- index = Index(ndim=ndim, metric_pointer=python_dot.address)
311
+ index = Index(ndim=ndim, metric=python_dot.address)
312
312
  ```
313
313
 
314
314
  [numba]: https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 0.11.0
package/binding.gyp CHANGED
@@ -10,6 +10,7 @@
10
10
  "include",
11
11
  "src",
12
12
  "fp16/include",
13
+ "robin-map/include",
13
14
  "simsimd/include"
14
15
  ],
15
16
  "dependencies": [
@@ -23,9 +24,9 @@
23
24
  "MACOSX_DEPLOYMENT_TARGET": "10.15"
24
25
  },
25
26
  "msvs_settings": {
26
- "VCCLCompilerTool": {
27
- "ExceptionHandling": 1,
28
- "AdditionalOptions": [ "-std:c++11" ]
27
+ "VCCLCompilerTool": {
28
+ "ExceptionHandling": 1,
29
+ "AdditionalOptions": ["-std:c++11"]
29
30
  }
30
31
  }
31
32
  }
package/build.gradle CHANGED
@@ -45,7 +45,7 @@ model {
45
45
  include "**/*.cpp"
46
46
  }
47
47
  exportedHeaders {
48
- srcDirs "include", "src", "fp16/include", "simsimd/include", "${Jvm.current().javaHome}/include"
48
+ srcDirs "include", "src", "fp16/include", "robin-map/include", "simsimd/include", "${Jvm.current().javaHome}/include"
49
49
  }
50
50
  }
51
51
  }
package/build.rs CHANGED
@@ -7,6 +7,7 @@ fn main() {
7
7
  .include("rust")
8
8
  .include("src")
9
9
  .include("fp16/include")
10
+ .include("robin-map/include")
10
11
  .include("simsimd/include")
11
12
  .compile("usearch");
12
13
 
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 = '0.10.0'
7
+ version = '0.11.0'
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'
@@ -63,8 +63,7 @@ Benchmarking:
63
63
  ## Python
64
64
 
65
65
  ```sh
66
- pip install -e .
67
- pytest python/scripts/test.py
66
+ pip install -e . && pytest python/scripts/test.py
68
67
  ```
69
68
 
70
69
  Linting:
@@ -131,7 +130,11 @@ g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
131
130
 
132
131
  # MacOS
133
132
  g++ -std=c++11 -c -fPIC \
134
- -I../../../../include -I../../../../src -I../../../../fp16/include -I../../../../simsimd/include \
133
+ -I../../../../include \
134
+ -I../../../../src \
135
+ -I../../../../fp16/include \
136
+ -I../../../../robin-map/include \
137
+ -I../../../../simsimd/include \
135
138
  -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
136
139
  g++ -dynamiclib -o libusearch.dylib cloud_unum_usearch_Index.o -lc
137
140
  # Run linking to that directory
@@ -9,6 +9,18 @@
9
9
  #ifndef UNUM_USEARCH_H
10
10
  #define UNUM_USEARCH_H
11
11
 
12
+ #if !defined(USEARCH_VERSION_MAJOR)
13
+ #define USEARCH_VERSION_MAJOR 0
14
+ #endif
15
+
16
+ #if !defined(USEARCH_VERSION_MINOR)
17
+ #define USEARCH_VERSION_MINOR 0
18
+ #endif
19
+
20
+ #if !defined(USEARCH_VERSION_PATCH)
21
+ #define USEARCH_VERSION_PATCH 0
22
+ #endif
23
+
12
24
  // Inferring C++ version
13
25
  #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
14
26
  #define USEARCH_IS_CPP17
@@ -61,7 +73,7 @@
61
73
  #include <mutex> // `std::unique_lock` - replacement candidate
62
74
  #include <random> // `std::default_random_engine` - replacement candidate
63
75
  #include <stdexcept> // `std::runtime_exception`
64
- #include <utility> // `std::exchange`, `std::pair`
76
+ #include <utility> // `std::pair`
65
77
  #include <vector> // `std::vector`
66
78
 
67
79
  // Prefetching
@@ -125,12 +137,20 @@ inline std::size_t ceil2(std::size_t v) noexcept {
125
137
 
126
138
  template <typename at> void misaligned_store(void* ptr, at v) noexcept { std::memcpy(ptr, &v, sizeof(v)); }
127
139
 
140
+ /// @brief Simply dereferencing misaligned pointers can be dangerous.
128
141
  template <typename at> at misaligned_load(void* ptr) noexcept {
129
142
  at v;
130
143
  std::memcpy(&v, ptr, sizeof(v));
131
144
  return v;
132
145
  }
133
146
 
147
+ /// @brief The `std::exchange` alternative for C++11.
148
+ template <typename at, typename other_at = at> at exchange(at& obj, other_at&& new_value) {
149
+ at old_value = std::move(obj);
150
+ obj = std::forward<other_at>(new_value);
151
+ return old_value;
152
+ }
153
+
134
154
  template <typename at> class misaligned_ref_gt {
135
155
  byte_t* ptr_;
136
156
 
@@ -141,10 +161,8 @@ template <typename at> class misaligned_ref_gt {
141
161
  misaligned_store<at>(ptr_, v);
142
162
  return *this;
143
163
  }
144
- misaligned_ref_gt& operator=(at v) noexcept {
145
- misaligned_store<at>(ptr_, v);
146
- return *this;
147
- }
164
+
165
+ void reset(byte_t* ptr) noexcept { ptr_ = ptr; }
148
166
  };
149
167
 
150
168
  template <typename at> class misaligned_ptr_gt {
@@ -783,6 +801,12 @@ constexpr std::size_t default_expansion_add() { return 128; }
783
801
  constexpr std::size_t default_expansion_search() { return 64; }
784
802
  constexpr std::size_t default_allocator_entry_bytes() { return 64; }
785
803
 
804
+ /**
805
+ * @brief The "magic" sequence helps infer the type of the file.
806
+ * USearch indexes start with the "unumusearch" string.
807
+ */
808
+ static constexpr char const* default_magic() { return "unumusearch"; }
809
+
786
810
  /**
787
811
  * @brief Configuration settings for the index construction.
788
812
  * Includes the main `::connectivity` parameter (`M` in the paper)
@@ -809,6 +833,7 @@ struct config_t {
809
833
  std::size_t max_elements = 0;
810
834
  std::size_t max_threads_add = 1;
811
835
  std::size_t max_threads_search = 1;
836
+ std::size_t vector_alignment = 1;
812
837
 
813
838
  std::size_t max_threads() const noexcept { return (std::max)(max_threads_add, max_threads_search); }
814
839
  std::size_t concurrency() const noexcept { return (std::min)(max_threads_add, max_threads_search); }
@@ -826,6 +851,67 @@ struct search_config_t {
826
851
  bool exact{};
827
852
  };
828
853
 
854
+ using file_header_t = byte_t[64];
855
+
856
+ /**
857
+ * @brief Serialized binary representations of the USearch index start with metadata.
858
+ * Metadata is parsed into a `file_head_t`, containing the USearch package version,
859
+ * and the properties of the index.
860
+ */
861
+ struct file_head_t {
862
+
863
+ using magic_t = char[11];
864
+ using version_major_t = std::uint16_t;
865
+ using version_minor_t = std::uint16_t;
866
+ using version_patch_t = std::uint16_t;
867
+
868
+ enum metric_t : std::uint8_t {
869
+ unknown_k = 0,
870
+ ip_k = 'i',
871
+ cos_k = 'c',
872
+ l2sq_k = 'e',
873
+ jaccard_k = 'j',
874
+ hamming_k = 'h',
875
+ pearson_k = 'p',
876
+ haversine_k = 'h',
877
+ };
878
+
879
+ using connectivity_t = std::uint8_t;
880
+ using max_level_t = std::uint8_t;
881
+ using vector_alignment_t = std::uint8_t;
882
+ using bytes_per_label_t = std::uint16_t;
883
+ using bytes_per_id_t = std::uint16_t;
884
+ using size_t = std::uint64_t;
885
+ using entry_idx_t = std::uint64_t;
886
+
887
+ char const* magic;
888
+ misaligned_ref_gt<version_major_t> version_major;
889
+ misaligned_ref_gt<version_minor_t> version_minor;
890
+ misaligned_ref_gt<version_patch_t> version_patch;
891
+ misaligned_ref_gt<metric_t> metric;
892
+ misaligned_ref_gt<connectivity_t> connectivity;
893
+ misaligned_ref_gt<max_level_t> max_level;
894
+ misaligned_ref_gt<vector_alignment_t> vector_alignment;
895
+ misaligned_ref_gt<bytes_per_label_t> bytes_per_label;
896
+ misaligned_ref_gt<bytes_per_id_t> bytes_per_id;
897
+ misaligned_ref_gt<size_t> size;
898
+ misaligned_ref_gt<entry_idx_t> entry_idx;
899
+
900
+ file_head_t(byte_t* ptr) noexcept
901
+ : magic((char const*)exchange(ptr, ptr + sizeof(magic_t))),
902
+ version_major(exchange(ptr, ptr + sizeof(version_major_t))),
903
+ version_minor(exchange(ptr, ptr + sizeof(version_minor_t))),
904
+ version_patch(exchange(ptr, ptr + sizeof(version_patch_t))), metric(exchange(ptr, ptr + sizeof(metric_t))),
905
+ connectivity(exchange(ptr, ptr + sizeof(connectivity_t))),
906
+ max_level(exchange(ptr, ptr + sizeof(max_level_t))),
907
+ vector_alignment(exchange(ptr, ptr + sizeof(vector_alignment_t))),
908
+ bytes_per_label(exchange(ptr, ptr + sizeof(bytes_per_label_t))),
909
+ bytes_per_id(exchange(ptr, ptr + sizeof(bytes_per_id_t))), size(exchange(ptr, ptr + sizeof(size_t))),
910
+ entry_idx(exchange(ptr, ptr + sizeof(entry_idx_t))) {}
911
+ };
912
+
913
+ static_assert(sizeof(file_header_t) == 64, "File header should be exactly 64 bytes");
914
+
829
915
  /**
830
916
  * @brief Approximate Nearest Neighbors Search index using the
831
917
  * Hierarchical Navigable Small World graph algorithm.
@@ -917,14 +1003,15 @@ class index_gt {
917
1003
  vector_view_t vector;
918
1004
  };
919
1005
 
920
- template <typename ref_at> class member_iterator_gt {
1006
+ template <typename ref_at, typename index_at> class member_iterator_gt {
921
1007
  using ref_t = ref_at;
922
- index_gt* index_{};
1008
+ using index_t = index_at;
1009
+ index_t* index_{};
923
1010
  std::size_t offset_{};
924
1011
 
925
1012
  friend class index_gt;
926
1013
  member_iterator_gt() noexcept {}
927
- member_iterator_gt(index_gt* index, std::size_t offset) noexcept : index_(index), offset_(offset) {}
1014
+ member_iterator_gt(index_t* index, std::size_t offset) noexcept : index_(index), offset_(offset) {}
928
1015
 
929
1016
  public:
930
1017
  using iterator_category = std::random_access_iterator_tag;
@@ -933,7 +1020,7 @@ class index_gt {
933
1020
  using pointer = void;
934
1021
  using reference = ref_t;
935
1022
 
936
- reference operator*() const noexcept { return index_->node_with_id_(offset_).ref(); }
1023
+ reference operator*() const noexcept { return ref_t(index_->node_with_id_(offset_)); }
937
1024
  member_iterator_gt operator++(int) noexcept { return member_iterator_gt(index_, offset_ + 1); }
938
1025
  member_iterator_gt operator--(int) noexcept { return member_iterator_gt(index_, offset_ - 1); }
939
1026
  member_iterator_gt operator+(difference_type d) noexcept { return member_iterator_gt(index_, offset_ + d); }
@@ -963,8 +1050,8 @@ class index_gt {
963
1050
  }
964
1051
  };
965
1052
 
966
- using member_iterator_t = member_iterator_gt<member_ref_t>;
967
- using member_citerator_t = member_iterator_gt<member_cref_t>;
1053
+ using member_iterator_t = member_iterator_gt<member_ref_t, index_gt>;
1054
+ using member_citerator_t = member_iterator_gt<member_cref_t, index_gt const>;
968
1055
 
969
1056
  // STL compatibility:
970
1057
  using value_type = std::pair<label_t, distance_t>;
@@ -1051,8 +1138,8 @@ class index_gt {
1051
1138
 
1052
1139
  operator vector_view_t() const noexcept { return {vector(), dim()}; }
1053
1140
  vector_view_t vector_view() const noexcept { return {vector(), dim()}; }
1054
- member_ref_t ref() noexcept { return {{tape_}, vector_view()}; }
1055
- member_cref_t cref() const noexcept { return {label(), vector_view()}; }
1141
+ explicit operator member_ref_t() noexcept { return {{tape_}, vector_view()}; }
1142
+ explicit operator member_cref_t() const noexcept { return {label(), vector_view()}; }
1056
1143
  };
1057
1144
 
1058
1145
  /**
@@ -1274,7 +1361,7 @@ class index_gt {
1274
1361
  inline std::size_t size() const noexcept { return count; }
1275
1362
  inline search_result_t operator[](std::size_t i) const noexcept {
1276
1363
  candidate_t const* top_ordered = top_.data();
1277
- return {index_.node_with_id_(top_ordered[i].id).cref(), top_ordered[i].distance};
1364
+ return {member_cref_t(index_.node_with_id_(top_ordered[i].id)), top_ordered[i].distance};
1278
1365
  }
1279
1366
  inline std::size_t dump_to(label_t* labels, distance_t* distances) const noexcept {
1280
1367
  for (std::size_t i = 0; i != count; ++i) {
@@ -1479,25 +1566,16 @@ class index_gt {
1479
1566
 
1480
1567
  void change_expansion_add(std::size_t n) noexcept { config_.expansion_add = n; }
1481
1568
  void change_expansion_search(std::size_t n) noexcept { config_.expansion_search = n; }
1569
+ void change_metric(metric_t const& m) noexcept(false) {
1570
+ metric_ = m;
1571
+ for (thread_context_t& context : thread_contexts_)
1572
+ context.metric = metric_;
1573
+ }
1482
1574
 
1483
1575
  #pragma endregion
1484
1576
 
1485
1577
  #pragma region Serialization
1486
1578
 
1487
- private:
1488
- struct serialized_state_t {
1489
- // Check compatibility
1490
- std::uint64_t bytes_per_label{};
1491
- std::uint64_t bytes_per_id{};
1492
-
1493
- // Describe state
1494
- std::uint64_t connectivity{};
1495
- std::uint64_t size{};
1496
- std::uint64_t entry_id{};
1497
- std::uint64_t max_level{};
1498
- };
1499
-
1500
- public:
1501
1579
  /**
1502
1580
  * @brief Saves serialized binary index representation to disk,
1503
1581
  * co-locating vectors and neighbors lists.
@@ -1505,15 +1583,25 @@ class index_gt {
1505
1583
  */
1506
1584
  void save(char const* file_path) const noexcept(false) {
1507
1585
 
1508
- serialized_state_t state;
1586
+ file_header_t state_buffer{};
1587
+ std::memset(state_buffer, 0, sizeof(file_header_t));
1588
+ file_head_t state{state_buffer};
1589
+ std::memcpy(state_buffer, default_magic(), std::strlen(default_magic()));
1590
+
1509
1591
  // Check compatibility
1510
- state.bytes_per_label = sizeof(label_t);
1511
- state.bytes_per_id = sizeof(id_t);
1592
+ state.version_major = USEARCH_VERSION_MAJOR;
1593
+ state.version_minor = USEARCH_VERSION_MINOR;
1594
+ state.version_patch = USEARCH_VERSION_PATCH;
1595
+ state.metric = file_head_t::unknown_k;
1596
+
1512
1597
  // Describe state
1513
1598
  state.connectivity = config_.connectivity;
1514
- state.size = size_;
1515
- state.entry_id = entry_id_;
1516
1599
  state.max_level = max_level_;
1600
+ state.vector_alignment = config_.vector_alignment;
1601
+ state.bytes_per_label = sizeof(label_t);
1602
+ state.bytes_per_id = sizeof(id_t);
1603
+ state.size = size_;
1604
+ state.entry_idx = entry_id_;
1517
1605
 
1518
1606
  std::FILE* file = std::fopen(file_path, "w");
1519
1607
  if (!file)
@@ -1528,7 +1616,7 @@ class index_gt {
1528
1616
  };
1529
1617
 
1530
1618
  // Write the header
1531
- write_chunk(&state, sizeof(state));
1619
+ write_chunk(&state_buffer[0], sizeof(file_header_t));
1532
1620
 
1533
1621
  // Serialize nodes one by one
1534
1622
  for (std::size_t i = 0; i != state.size; ++i) {
@@ -1549,7 +1637,7 @@ class index_gt {
1549
1637
  * Available on Linux, MacOS, Windows.
1550
1638
  */
1551
1639
  void load(char const* file_path) noexcept(false) {
1552
- serialized_state_t state;
1640
+ file_header_t state_buffer{};
1553
1641
  std::FILE* file = std::fopen(file_path, "r");
1554
1642
  if (!file)
1555
1643
  throw std::runtime_error(std::strerror(errno));
@@ -1564,7 +1652,8 @@ class index_gt {
1564
1652
 
1565
1653
  // Read the header
1566
1654
  {
1567
- read_chunk(&state, sizeof(state));
1655
+ read_chunk(&state_buffer[0], sizeof(file_header_t));
1656
+ file_head_t state{state_buffer};
1568
1657
  if (state.bytes_per_label != sizeof(label_t)) {
1569
1658
  std::fclose(file);
1570
1659
  throw std::runtime_error("Incompatible label type!");
@@ -1576,15 +1665,16 @@ class index_gt {
1576
1665
 
1577
1666
  config_.connectivity = state.connectivity;
1578
1667
  config_.max_elements = state.size;
1668
+ config_.vector_alignment = state.vector_alignment;
1579
1669
  pre_ = precompute_(config_);
1580
1670
  reserve(state.size);
1581
1671
  size_ = state.size;
1582
1672
  max_level_ = static_cast<level_t>(state.max_level);
1583
- entry_id_ = static_cast<id_t>(state.entry_id);
1673
+ entry_id_ = static_cast<id_t>(state.entry_idx);
1584
1674
  }
1585
1675
 
1586
1676
  // Load nodes one by one
1587
- for (std::size_t i = 0; i != state.size; ++i) {
1677
+ for (std::size_t i = 0; i != size_; ++i) {
1588
1678
  label_t label;
1589
1679
  dim_t dim;
1590
1680
  level_t level;
@@ -1611,7 +1701,6 @@ class index_gt {
1611
1701
  #if defined(USEARCH_IS_WINDOWS)
1612
1702
  throw std::logic_error("Memory-mapping is not yet available for Windows");
1613
1703
  #else
1614
- serialized_state_t state;
1615
1704
  int open_flags = O_RDONLY;
1616
1705
  #if __linux__
1617
1706
  open_flags |= O_NOATIME;
@@ -1635,7 +1724,7 @@ class index_gt {
1635
1724
 
1636
1725
  // Read the header
1637
1726
  {
1638
- std::memcpy(&state, file, sizeof(state));
1727
+ file_head_t state{file};
1639
1728
  if (state.bytes_per_label != sizeof(label_t)) {
1640
1729
  close(descriptor);
1641
1730
  throw std::runtime_error("Incompatible label type!");
@@ -1647,17 +1736,18 @@ class index_gt {
1647
1736
 
1648
1737
  config_.connectivity = state.connectivity;
1649
1738
  config_.max_elements = state.size;
1739
+ config_.vector_alignment = state.vector_alignment;
1650
1740
  config_.max_threads_add = 0;
1651
1741
  pre_ = precompute_(config_);
1652
1742
  reserve(state.size);
1653
1743
  size_ = state.size;
1654
1744
  max_level_ = static_cast<level_t>(state.max_level);
1655
- entry_id_ = static_cast<id_t>(state.entry_id);
1745
+ entry_id_ = static_cast<id_t>(state.entry_idx);
1656
1746
  }
1657
1747
 
1658
1748
  // Locate every node packed into file
1659
- std::size_t progress = sizeof(state);
1660
- for (std::size_t i = 0; i != state.size; ++i) {
1749
+ std::size_t progress = sizeof(file_header_t);
1750
+ for (std::size_t i = 0; i != size_; ++i) {
1661
1751
  byte_t* tape = (byte_t*)(file + progress);
1662
1752
  dim_t dim = misaligned_load<dim_t>(tape + sizeof(label_t));
1663
1753
  level_t level = misaligned_load<level_t>(tape + sizeof(label_t) + sizeof(dim_t));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usearch",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Smaller & Faster Single-File Vector Search Engine from Unum",
5
5
  "author": "Ashot Vardanian",
6
6
  "license": "Apache 2.0",