Repository: unum-cloud/usearch (language: python)

Issue:
Feature: parsing more complex tensor's scalars types
### Describe what you are looking for

Currently, usearch can parse only exact dtypes (f8, f32 and etc). But tensors can have more complex description of scalars' type. For instance, numpy `__array_interface__` property can return something like this:

`{'data': (140283485917200, False), 'strides': None, 'descr': [('', '<f4')], 'typestr': '<f4', 'shape': (1183514, 100), 'version': 3}`

So, it'd be useful If usearch supported dtypes like this.

### Can you contribute to the implementation?

- [ ] I can contribute

### Is your feature request specific to a certain interface?

It applies to everything

### Contact Details

_No response_

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c930abc8..9dc69dfd 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -231,7 +231,7 @@ jobs:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         with:
           file: docs.tar.gz
-          asset_name: docs.tar.gz
+          update_latest_release: true
 
   deploy_docs_pages:
     name: Deploy GitHub Pages
diff --git a/.gitmodules b/.gitmodules
index d6efee91..527e224d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "fp16"]
 	path = fp16
 	url = https://github.com/maratyszcza/fp16
+[submodule "robin-map"]
+	path = robin-map
+	url = https://github.com/tessil/robin-map
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 7522665a..c1e5e96d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -125,10 +125,12 @@
         "OPENMP",
         "preprocess",
         "Quickstart",
+        "rtype",
         "simsimd",
         "SLOC",
         "usearch",
         "usecases"
     ],
+    "autoDocstring.docstringFormat": "sphinx",
     "java.configuration.updateBuildConfiguration": "interactive"
 }
\ No newline at end of file
diff --git a/Package.swift b/Package.swift
index ffbcf930..0fa7b683 100644
--- a/Package.swift
+++ b/Package.swift
@@ -20,6 +20,7 @@ let package = Package(
                 .headerSearchPath("../include/"),
                 .headerSearchPath("../src/"),
                 .headerSearchPath("../fp16/include/"),
+                .headerSearchPath("../robin-map/include/"),
                 .headerSearchPath("../simismd/include/")
             ]
         ),
diff --git a/README.md b/README.md
index 99433fba..d0be0189 100644
--- a/README.md
+++ b/README.md
@@ -308,7 +308,7 @@ def python_dot(a, b, n, m):
         c += a_array[i] * b_array[i]
     return c
 
-index = Index(ndim=ndim, metric_pointer=python_dot.address)
+index = Index(ndim=ndim, metric=python_dot.address)
 ```
 
 [numba]: https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
diff --git a/binding.gyp b/binding.gyp
index 8c1a2e37..7bfb21a6 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -10,6 +10,7 @@
                 "include",
                 "src",
                 "fp16/include",
+                "robin-map/include",
                 "simsimd/include"
             ],
             "dependencies": [
@@ -23,9 +24,9 @@
                 "MACOSX_DEPLOYMENT_TARGET": "10.15"
             },
             "msvs_settings": {
-                "VCCLCompilerTool": { 
-                    "ExceptionHandling": 1, 
-                    "AdditionalOptions": [ "-std:c++11" ]
+                "VCCLCompilerTool": {
+                    "ExceptionHandling": 1,
+                    "AdditionalOptions": ["-std:c++11"]
                 }
             }
         }
diff --git a/build.gradle b/build.gradle
index 64799510..91fb5184 100644
--- a/build.gradle
+++ b/build.gradle
@@ -45,7 +45,7 @@ model {
                         include "**/*.cpp"
                     }
                     exportedHeaders {
-                        srcDirs "include", "src", "fp16/include", "simsimd/include", "${Jvm.current().javaHome}/include"
+                        srcDirs "include", "src", "fp16/include", "robin-map/include", "simsimd/include", "${Jvm.current().javaHome}/include"
                     }
                 }
             }
diff --git a/build.rs b/build.rs
index f6079b9a..381fde0c 100644
--- a/build.rs
+++ b/build.rs
@@ -7,6 +7,7 @@ fn main() {
         .include("rust")
         .include("src")
         .include("fp16/include")
+        .include("robin-map/include")
         .include("simsimd/include")
         .compile("usearch");
 
diff --git a/docs/compilation.md b/docs/compilation.md
index e90a1a27..9ba03337 100644
--- a/docs/compilation.md
+++ b/docs/compilation.md
@@ -63,8 +63,7 @@ Benchmarking:
 ## Python
 
 ```sh
-pip install -e .
-pytest python/scripts/test.py
+pip install -e . && pytest python/scripts/test.py
 ```
 
 Linting:
@@ -131,7 +130,11 @@ g++ -shared -o USearchJNI.dll cloud_unum_usearch_Index.o -Wl,--add-stdcall-alias
 
 # MacOS
 g++ -std=c++11 -c -fPIC \
-    -I../../../../include -I../../../../src -I../../../../fp16/include -I../../../../simsimd/include \
+    -I../../../../include \
+    -I../../../../src \
+    -I../../../../fp16/include \
+    -I../../../../robin-map/include \
+    -I../../../../simsimd/include \
     -I${JAVA_HOME}/include -I${JAVA_HOME}/include/darwin cloud_unum_usearch_Index.cpp -o cloud_unum_usearch_Index.o
 g++ -dynamiclib -o libusearch.dylib cloud_unum_usearch_Index.o -lc
 # Run linking to that directory
diff --git a/include/usearch/usearch.hpp b/include/usearch/usearch.hpp
index d4b738f7..5ef33820 100644
--- a/include/usearch/usearch.hpp
+++ b/include/usearch/usearch.hpp
@@ -9,6 +9,18 @@
 #ifndef UNUM_USEARCH_H
 #define UNUM_USEARCH_H
 
+#if !defined(USEARCH_VERSION_MAJOR)
+#define USEARCH_VERSION_MAJOR 0
+#endif
+
+#if !defined(USEARCH_VERSION_MINOR)
+#define USEARCH_VERSION_MINOR 0
+#endif
+
+#if !defined(USEARCH_VERSION_PATCH)
+#define USEARCH_VERSION_PATCH 0
+#endif
+
 // Inferring C++ version
 #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
 #define USEARCH_IS_CPP17
@@ -61,7 +73,7 @@
 #include <mutex>     // `std::unique_lock` - replacement candidate
 #include <random>    // `std::default_random_engine` - replacement candidate
 #include <stdexcept> // `std::runtime_exception`
-#include <utility>   // `std::exchange`, `std::pair`
+#include <utility>   // `std::pair`
 #include <vector>    // `std::vector`
 
 // Prefetching
@@ -125,12 +137,20 @@ inline std::size_t ceil2(std::size_t v) noexcept {
 
 template <typename at> void misaligned_store(void* ptr, at v) noexcept { std::memcpy(ptr, &v, sizeof(v)); }
 
+/// @brief  Simply dereferencing misaligned pointers can be dangerous.
 template <typename at> at misaligned_load(void* ptr) noexcept {
     at v;
     std::memcpy(&v, ptr, sizeof(v));
     return v;
 }
 
+/// @brief  The `std::exchange` alternative for C++11.
+template <typename at, typename other_at = at> at exchange(at& obj, other_at&& new_value) {
+    at old_value = std::move(obj);
+    obj = std::forward<other_at>(new_value);
+    return old_value;
+}
+
 template <typename at> class misaligned_ref_gt {
     byte_t* ptr_;
 
@@ -141,10 +161,8 @@ template <typename at> class misaligned_ref_gt {
         misaligned_store<at>(ptr_, v);
         return *this;
     }
-    misaligned_ref_gt& operator=(at v) noexcept {
-        misaligned_store<at>(ptr_, v);
-        return *this;
-    }
+
+    void reset(byte_t* ptr) noexcept { ptr_ = ptr; }
 };
 
 template <typename at> class misaligned_ptr_gt {
@@ -783,6 +801,12 @@ constexpr std::size_t default_expansion_add() { return 128; }
 constexpr std::size_t default_expansion_search() { return 64; }
 constexpr std::size_t default_allocator_entry_bytes() { return 64; }
 
+/**
+ *  @brief  The "magic" sequence helps infer the type of the file.
+ *          USearch indexes start with the "unumusearch" string.
+ */
+static constexpr char const* default_magic() { return "unumusearch"; }
+
 /**
  *  @brief  Configuration settings for the index construction.
  *          Includes the main `::connectivity` parameter (`M` in the paper)
@@ -809,6 +833,7 @@ struct config_t {
     std::size_t max_elements = 0;
     std::size_t max_threads_add = 1;
     std::size_t max_threads_search = 1;
+    std::size_t vector_alignment = 1;
 
     std::size_t max_threads() const noexcept { return (std::max)(max_threads_add, max_threads_search); }
     std::size_t concurrency() const noexcept { return (std::min)(max_threads_add, max_threads_search); }
@@ -826,6 +851,67 @@ struct search_config_t {
     bool exact{};
 };
 
+using file_header_t = byte_t[64];
+
+/**
+ *  @brief  Serialized binary representations of the USearch index start with metadata.
+ *          Metadata is parsed into a `file_head_t`, containing the USearch package version,
+ *          and the properties of the index.
+ */
+struct file_head_t {
+
+    using magic_t = char[11];
+    using version_major_t = std::uint16_t;
+    using version_minor_t = std::uint16_t;
+    using version_patch_t = std::uint16_t;
+
+    enum metric_t : std::uint8_t {
+        unknown_k = 0,
+        ip_k = 'i',
+        cos_k = 'c',
+        l2sq_k = 'e',
+        jaccard_k = 'j',
+        hamming_k = 'h',
+        pearson_k = 'p',
+        haversine_k = 'h',
+    };
+
+    using connectivity_t = std::uint8_t;
+    using max_level_t = std::uint8_t;
+    using vector_alignment_t = std::uint8_t;
+    using bytes_per_label_t = std::uint16_t;
+    using bytes_per_id_t = std::uint16_t;
+    using size_t = std::uint64_t;
+    using entry_idx_t = std::uint64_t;
+
+    char const* magic;
+    misaligned_ref_gt<version_major_t> version_major;
+    misaligned_ref_gt<version_minor_t> version_minor;
+    misaligned_ref_gt<version_patch_t> version_patch;
+    misaligned_ref_gt<metric_t> metric;
+    misaligned_ref_gt<connectivity_t> connectivity;
+    misaligned_ref_gt<max_level_t> max_level;
+    misaligned_ref_gt<vector_alignment_t> vector_alignment;
+    misaligned_ref_gt<bytes_per_label_t> bytes_per_label;
+    misaligned_ref_gt<bytes_per_id_t> bytes_per_id;
+    misaligned_ref_gt<size_t> size;
+    misaligned_ref_gt<entry_idx_t> entry_idx;
+
+    file_head_t(byte_t* ptr) noexcept
+        : magic((char const*)exchange(ptr, ptr + sizeof(magic_t))),
+          version_major(exchange(ptr, ptr + sizeof(version_major_t))),
+          version_minor(exchange(ptr, ptr + sizeof(version_minor_t))),
+          version_patch(exchange(ptr, ptr + sizeof(version_patch_t))), metric(exchange(ptr, ptr + sizeof(metric_t))),
+          connectivity(exchange(ptr, ptr + sizeof(connectivity_t))),
+          max_level(exchange(ptr, ptr + sizeof(max_level_t))),
+          vector_alignment(exchange(ptr, ptr + sizeof(vector_alignment_t))),
+          bytes_per_label(exchange(ptr, ptr + sizeof(bytes_per_label_t))),
+          bytes_per_id(exchange(ptr, ptr + sizeof(bytes_per_id_t))), size(exchange(ptr, ptr + sizeof(size_t))),
+          entry_idx(exchange(ptr, ptr + sizeof(entry_idx_t))) {}
+};
+
+static_assert(sizeof(file_header_t) == 64, "File header should be exactly 64 bytes");
+
 /**
  *  @brief  Approximate Nearest Neighbors Search index using the
  *          Hierarchical Navigable Small World graph algorithm.
@@ -917,14 +1003,15 @@ class index_gt {
         vector_view_t vector;
     };
 
-    template <typename ref_at> class member_iterator_gt {
+    template <typename ref_at, typename index_at> class member_iterator_gt {
         using ref_t = ref_at;
-        index_gt* index_{};
+        using index_t = index_at;
+        index_t* index_{};
         std::size_t offset_{};
 
         friend class index_gt;
         member_iterator_gt() noexcept {}
-        member_iterator_gt(index_gt* index, std::size_t offset) noexcept : index_(index), offset_(offset) {}
+        member_iterator_gt(index_t* index, std::size_t offset) noexcept : index_(index), offset_(offset) {}
 
       public:
         using iterator_category = std::random_access_iterator_tag;
@@ -933,7 +1020,7 @@ class index_gt {
         using pointer = void;
         using reference = ref_t;
 
-        reference operator*() const noexcept { return index_->node_with_id_(offset_).ref(); }
+        reference operator*() const noexcept { return ref_t(index_->node_with_id_(offset_)); }
         member_iterator_gt operator++(int) noexcept { return member_iterator_gt(index_, offset_ + 1); }
         member_iterator_gt operator--(int) noexcept { return member_iterator_gt(index_, offset_ - 1); }
         member_iterator_gt operator+(difference_type d) noexcept { return member_iterator_gt(index_, offset_ + d); }
@@ -963,8 +1050,8 @@ class index_gt {
         }
     };
 
-    using member_iterator_t = member_iterator_gt<member_ref_t>;
-    using member_citerator_t = member_iterator_gt<member_cref_t>;
+    using member_iterator_t = member_iterator_gt<member_ref_t, index_gt>;
+    using member_citerator_t = member_iterator_gt<member_cref_t, index_gt const>;
 
     // STL compatibility:
     using value_type = std::pair<label_t, distance_t>;
@@ -1051,8 +1138,8 @@ class index_gt {
 
         operator vector_view_t() const noexcept { return {vector(), dim()}; }
         vector_view_t vector_view() const noexcept { return {vector(), dim()}; }
-        member_ref_t ref() noexcept { return {{tape_}, vector_view()}; }
-        member_cref_t cref() const noexcept { return {label(), vector_view()}; }
+        explicit operator member_ref_t() noexcept { return {{tape_}, vector_view()}; }
+        explicit operator member_cref_t() const noexcept { return {label(), vector_view()}; }
     };
 
     /**
@@ -1274,7 +1361,7 @@ class index_gt {
         inline std::size_t size() const noexcept { return count; }
         inline search_result_t operator[](std::size_t i) const noexcept {
             candidate_t const* top_ordered = top_.data();
-            return {index_.node_with_id_(top_ordered[i].id).cref(), top_ordered[i].distance};
+            return {member_cref_t(index_.node_with_id_(top_ordered[i].id)), top_ordered[i].distance};
         }
         inline std::size_t dump_to(label_t* labels, distance_t* distances) const noexcept {
             for (std::size_t i = 0; i != count; ++i) {
@@ -1479,25 +1566,16 @@ class index_gt {
 
     void change_expansion_add(std::size_t n) noexcept { config_.expansion_add = n; }
     void change_expansion_search(std::size_t n) noexcept { config_.expansion_search = n; }
+    void change_metric(metric_t const& m) noexcept(false) {
+        metric_ = m;
+        for (thread_context_t& context : thread_contexts_)
+            context.metric = metric_;
+    }
 
 #pragma endregion
 
 #pragma region Serialization
 
-  private:
-    struct serialized_state_t {
-        // Check compatibility
-        std::uint64_t bytes_per_label{};
-        std::uint64_t bytes_per_id{};
-
-        // Describe state
-        std::uint64_t connectivity{};
-        std::uint64_t size{};
-        std::uint64_t entry_id{};
-        std::uint64_t max_level{};
-    };
-
-  public:
     /**
      *  @brief  Saves serialized binary index representation to disk,
      *          co-locating vectors and neighbors lists.
@@ -1505,15 +1583,25 @@ class index_gt {
      */
     void save(char const* file_path) const noexcept(false) {
 
-        serialized_state_t state;
+        file_header_t state_buffer{};
+        std::memset(state_buffer, 0, sizeof(file_header_t));
+        file_head_t state{state_buffer};
+        std::memcpy(state_buffer, default_magic(), std::strlen(default_magic()));
+
         // Check compatibility
-        state.bytes_per_label = sizeof(label_t);
-        state.bytes_per_id = sizeof(id_t);
+        state.version_major = USEARCH_VERSION_MAJOR;
+        state.version_minor = USEARCH_VERSION_MINOR;
+        state.version_patch = USEARCH_VERSION_PATCH;
+        state.metric = file_head_t::unknown_k;
+
         // Describe state
         state.connectivity = config_.connectivity;
-        state.size = size_;
-        state.entry_id = entry_id_;
         state.max_level = max_level_;
+        state.vector_alignment = config_.vector_alignment;
+        state.bytes_per_label = sizeof(label_t);
+        state.bytes_per_id = sizeof(id_t);
+        state.size = size_;
+        state.entry_idx = entry_id_;
 
         std::FILE* file = std::fopen(file_path, "w");
         if (!file)
@@ -1528,7 +1616,7 @@ class index_gt {
         };
 
         // Write the header
-        write_chunk(&state, sizeof(state));
+        write_chunk(&state_buffer[0], sizeof(file_header_t));
 
         // Serialize nodes one by one
         for (std::size_t i = 0; i != state.size; ++i) {
@@ -1549,7 +1637,7 @@ class index_gt {
      *          Available on Linux, MacOS, Windows.
      */
     void load(char const* file_path) noexcept(false) {
-        serialized_state_t state;
+        file_header_t state_buffer{};
         std::FILE* file = std::fopen(file_path, "r");
         if (!file)
             throw std::runtime_error(std::strerror(errno));
@@ -1564,7 +1652,8 @@ class index_gt {
 
         // Read the header
         {
-            read_chunk(&state, sizeof(state));
+            read_chunk(&state_buffer[0], sizeof(file_header_t));
+            file_head_t state{state_buffer};
             if (state.bytes_per_label != sizeof(label_t)) {
                 std::fclose(file);
                 throw std::runtime_error("Incompatible label type!");
@@ -1576,15 +1665,16 @@ class index_gt {
 
             config_.connectivity = state.connectivity;
             config_.max_elements = state.size;
+            config_.vector_alignment = state.vector_alignment;
             pre_ = precompute_(config_);
             reserve(state.size);
             size_ = state.size;
             max_level_ = static_cast<level_t>(state.max_level);
-            entry_id_ = static_cast<id_t>(state.entry_id);
+            entry_id_ = static_cast<id_t>(state.entry_idx);
         }
 
         // Load nodes one by one
-        for (std::size_t i = 0; i != state.size; ++i) {
+        for (std::size_t i = 0; i != size_; ++i) {
             label_t label;
             dim_t dim;
             level_t level;
@@ -1611,7 +1701,6 @@ class index_gt {
 #if defined(USEARCH_IS_WINDOWS)
         throw std::logic_error("Memory-mapping is not yet available for Windows");
 #else
-        serialized_state_t state;
         int open_flags = O_RDONLY;
 #if __linux__
         open_flags |= O_NOATIME;
@@ -1635,7 +1724,7 @@ class index_gt {
 
         // Read the header
         {
-            std::memcpy(&state, file, sizeof(state));
+            file_head_t state{file};
             if (state.bytes_per_label != sizeof(label_t)) {
                 close(descriptor);
                 throw std::runtime_error("Incompatible label type!");
@@ -1647,17 +1736,18 @@ class index_gt {
 
             config_.connectivity = state.connectivity;
             config_.max_elements = state.size;
+            config_.vector_alignment = state.vector_alignment;
             config_.max_threads_add = 0;
             pre_ = precompute_(config_);
             reserve(state.size);
             size_ = state.size;
             max_level_ = static_cast<level_t>(state.max_level);
-            entry_id_ = static_cast<id_t>(state.entry_id);
+            entry_id_ = static_cast<id_t>(state.entry_idx);
         }
 
         // Locate every node packed into file
-        std::size_t progress = sizeof(state);
-        for (std::size_t i = 0; i != state.size; ++i) {
+        std::size_t progress = sizeof(file_header_t);
+        for (std::size_t i = 0; i != size_; ++i) {
             byte_t* tape = (byte_t*)(file + progress);
             dim_t dim = misaligned_load<dim_t>(tape + sizeof(label_t));
             level_t level = misaligned_load<level_t>(tape + sizeof(label_t) + sizeof(dim_t));
diff --git a/python/lib.cpp b/python/lib.cpp
index f0807727..d7e4ff9d 100644
--- a/python/lib.cpp
+++ b/python/lib.cpp
@@ -169,7 +169,7 @@ static std::unique_ptr<hash_index_py_t> make_hash_index( //
     return std::unique_ptr<hash_index_py_t>(new hash_index_py_t(config, bits));
 }
 
-static void add_one_to_index(punned_py_t& index, label_t label, py::buffer vector, bool copy) {
+static void add_one_to_index(punned_py_t& index, label_t label, py::buffer vector, bool copy, std::size_t) {
 
     py::buffer_info vector_info = vector.request();
     if (vector_info.ndim != 1)
@@ -191,9 +191,9 @@ static void add_one_to_index(punned_py_t& index, label_t label, py::buffer vecto
         index.add(label, reinterpret_cast<f8_bits_t const*>(vector_data), config);
     else if (vector_info.format == "e")
         index.add(label, reinterpret_cast<f16_bits_t const*>(vector_data), config);
-    else if (vector_info.format == "f")
+    else if (vector_info.format == "f" || vector_info.format == "f4" || vector_info.format == "<f4")
         index.add(label, reinterpret_cast<float const*>(vector_data), config);
-    else if (vector_info.format == "d")
+    else if (vector_info.format == "d" || vector_info.format == "f8" || vector_info.format == "<f8")
         index.add(label, reinterpret_cast<double const*>(vector_data), config);
     else
         throw std::invalid_argument("Incompatible scalars in the vector!");
@@ -201,7 +201,10 @@ static void add_one_to_index(punned_py_t& index, label_t label, py::buffer vecto
 
 static void add_many_to_index(                                 //
     punned_py_t& index, py::buffer labels, py::buffer vectors, //
-    bool copy, std::size_t threads = 0) {
+    bool copy, std::size_t threads) {
+
+    if (index.config().max_threads_add < threads)
+        throw std::invalid_argument("Can't use that many threads!");
 
     py::buffer_info labels_info = labels.request();
     py::buffer_info vectors_info = vectors.request();
@@ -232,7 +235,7 @@ static void add_many_to_index(                                 //
 
     // https://docs.python.org/3/library/struct.html#format-characters
     if (vectors_info.format == "c" || vectors_info.format == "b")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             add_config_t config;
             config.store_vector = copy;
             config.thread = thread_idx;
@@ -242,7 +245,7 @@ static void add_many_to_index(                                 //
             index.add(label, vector, config);
         });
     else if (vectors_info.format == "e")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             add_config_t config;
             config.store_vector = copy;
             config.thread = thread_idx;
@@ -251,8 +254,8 @@ static void add_many_to_index(                                 //
                 reinterpret_cast<f16_bits_t const*>(vectors_data + task_idx * vectors_info.strides[0]);
             index.add(label, vector, config);
         });
-    else if (vectors_info.format == "f")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+    else if (vectors_info.format == "f" || vectors_info.format == "f4" || vectors_info.format == "<f4")
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             add_config_t config;
             config.store_vector = copy;
             config.thread = thread_idx;
@@ -260,8 +263,8 @@ static void add_many_to_index(                                 //
             float const* vector = reinterpret_cast<float const*>(vectors_data + task_idx * vectors_info.strides[0]);
             index.add(label, vector, config);
         });
-    else if (vectors_info.format == "d")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+    else if (vectors_info.format == "d" || vectors_info.format == "f8" || vectors_info.format == "<f8")
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             add_config_t config;
             config.store_vector = copy;
             config.thread = thread_idx;
@@ -299,11 +302,11 @@ static py::tuple search_one_in_index(punned_py_t& index, py::buffer vector, std:
         count = index //
                     .search(reinterpret_cast<f16_bits_t const*>(vector_data), wanted, config)
                     .dump_to(&labels_py1d(0), &distances_py1d(0));
-    else if (vector_info.format == "f")
+    else if (vector_info.format == "f" || vector_info.format == "f4" || vector_info.format == "<f4")
         count = index //
                     .search(reinterpret_cast<float const*>(vector_data), wanted, config)
                     .dump_to(&labels_py1d(0), &distances_py1d(0));
-    else if (vector_info.format == "d")
+    else if (vector_info.format == "d" || vector_info.format == "f8" || vector_info.format == "<f8")
         count = index //
                     .search(reinterpret_cast<double const*>(vector_data), wanted, config)
                     .dump_to(&labels_py1d(0), &distances_py1d(0));
@@ -329,11 +332,15 @@ static py::tuple search_one_in_index(punned_py_t& index, py::buffer vector, std:
  *      2. matrix of distances,
  *      3. array with match counts.
  */
-static py::tuple search_many_in_index(punned_py_t& index, py::buffer vectors, std::size_t wanted, bool exact) {
+static py::tuple search_many_in_index( //
+    punned_py_t& index, py::buffer vectors, std::size_t wanted, bool exact, std::size_t threads) {
 
     if (wanted == 0)
         return py::tuple(3);
 
+    if (index.config().max_threads_add < threads)
+        throw std::invalid_argument("Can't use that many threads!");
+
     py::buffer_info vectors_info = vectors.request();
     if (vectors_info.ndim == 1)
         return search_one_in_index(index, vectors, wanted, exact);
@@ -355,7 +362,7 @@ static py::tuple search_many_in_index(punned_py_t& index, py::buffer vectors, st
 
     // https://docs.python.org/3/library/struct.html#format-characters
     if (vectors_info.format == "c" || vectors_info.format == "b")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             search_config_t config;
             config.thread = thread_idx;
             config.exact = exact;
@@ -364,7 +371,7 @@ static py::tuple search_many_in_index(punned_py_t& index, py::buffer vectors, st
                 index.search(vector, wanted, config).dump_to(&labels_py2d(task_idx, 0), &distances_py2d(task_idx, 0)));
         });
     else if (vectors_info.format == "e")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             search_config_t config;
             config.thread = thread_idx;
             config.exact = exact;
@@ -372,8 +379,8 @@ static py::tuple search_many_in_index(punned_py_t& index, py::buffer vectors, st
             counts_py1d(task_idx) = static_cast<Py_ssize_t>(
                 index.search(vector, wanted, config).dump_to(&labels_py2d(task_idx, 0), &distances_py2d(task_idx, 0)));
         });
-    else if (vectors_info.format == "f")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+    else if (vectors_info.format == "f" || vectors_info.format == "f4" || vectors_info.format == "<f4")
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             search_config_t config;
             config.thread = thread_idx;
             config.exact = exact;
@@ -381,8 +388,8 @@ static py::tuple search_many_in_index(punned_py_t& index, py::buffer vectors, st
             counts_py1d(task_idx) = static_cast<Py_ssize_t>(
                 index.search(vector, wanted, config).dump_to(&labels_py2d(task_idx, 0), &distances_py2d(task_idx, 0)));
         });
-    else if (vectors_info.format == "d")
-        multithreaded(index.config().concurrency(), vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
+    else if (vectors_info.format == "d" || vectors_info.format == "f8" || vectors_info.format == "<f8")
+        multithreaded(threads, vectors_count, [&](std::size_t thread_idx, std::size_t task_idx) {
             search_config_t config;
             config.thread = thread_idx;
             config.exact = exact;
@@ -407,7 +414,6 @@ template <typename index_at> void view_index(index_at& index, std::string const&
 template <typename index_at> void clear_index(index_at& index) { index.clear(); }
 template <typename index_at> std::size_t get_expansion_add(index_at const &index) { return index.config().expansion_add; }
 template <typename index_at> std::size_t get_expansion_search(index_at const &index) { return index.config().expansion_search; }
-
 // clang-format on
 
 template <typename element_at> bool has_duplicates(element_at const* begin, element_at const* end) {
@@ -476,8 +482,12 @@ void hash_buffer(hash_index_py_t& index, py::buffer vector) {
         throw std::invalid_argument("Array elements must be 16, 32, or 64 bit hashable integers!");
 }
 
-PYBIND11_MODULE(index, m) {
-    m.doc() = "Unum USearch Python bindings";
+PYBIND11_MODULE(compiled, m) {
+    m.doc() = "Smaller & Faster Single-File Vector Search Engine from Unum";
+
+    m.attr("DEFAULT_CONNECTIVITY") = py::int_(default_connectivity());
+    m.attr("DEFAULT_EXPANSION_ADD") = py::int_(default_expansion_add());
+    m.attr("DEFAULT_EXPANSION_SEARCH") = py::int_(default_expansion_search());
 
     auto i = py::class_<punned_py_t>(m, "Index");
 
@@ -508,14 +518,16 @@ PYBIND11_MODULE(index, m) {
         py::arg("label"),         //
         py::arg("vector"),        //
         py::kw_only(),            //
-        py::arg("copy") = true    //
+        py::arg("copy") = true,   //
+        py::arg("threads") = 0    //
     );
 
     i.def(                               //
         "search", &search_many_in_index, //
         py::arg("query"),                //
         py::arg("count") = 10,           //
-        py::arg("exact") = false         //
+        py::arg("exact") = false,        //
+        py::arg("threads") = 0           //
     );
 
     i.def("__len__", &punned_py_t::size);
diff --git a/python/scripts/bench.py b/python/scripts/bench.py
index 5989ea2f..a2e26f83 100644
--- a/python/scripts/bench.py
+++ b/python/scripts/bench.py
@@ -142,7 +142,7 @@ def cos_f8(a, b, n, m):
             expansion_add=expansion_add,
             expansion_search=expansion_search,
             connectivity=connectivity,
-            metric_pointer=inner_product_f32.address,
+            metric=inner_product_f32.address,
         )
         bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
 
@@ -153,7 +153,7 @@ def cos_f8(a, b, n, m):
             expansion_add=expansion_add,
             expansion_search=expansion_search,
             connectivity=connectivity,
-            metric_pointer=cos_f8.address,
+            metric=cos_f8.address,
         )
         bench_usearch(index, vectors_mat, queries_mat, neighbors_mat)
     except ImportError:
diff --git a/python/usearch/index.py b/python/usearch/index.py
new file mode 100644
index 00000000..cced0741
--- /dev/null
+++ b/python/usearch/index.py
@@ -0,0 +1,298 @@
+# The purpose of this file is to provide Pythonic wrapper on top
+# the native precompiled CPython module. It improves compatibility
+# Python tooling, linters, and static analyzers. It also embeds JIT
+# into the primary `Index` class, connecting USearch with Numba.
+import os
+from math import sqrt
+from typing import Optional, Callable, Union
+
+import numpy as np
+
+from usearch.compiled import Index as _CompiledIndex
+from usearch.compiled import SetsIndex as _CompiledSetsIndex
+from usearch.compiled import HashIndex as _CompiledHashIndex
+from usearch.compiled import DEFAULT_CONNECTIVITY, DEFAULT_EXPANSION_ADD, DEFAULT_EXPANSION_SEARCH
+
+Triplet = tuple[np.ndarray, np.ndarray, np.ndarray]
+SetsIndex = _CompiledSetsIndex
+HashIndex = _CompiledHashIndex
+
+
+def results_to_list(results: Triplet, row: int) -> list[dict]:
+
+    count = results[2][row]
+    labels = results[0][row, :count]
+    distances = results[1][row, :count]
+    return [
+        {'label': int(label), 'distance': float(distance)}
+        for label, distance in zip(labels, distances)
+    ]
+
+
+def jit_metric(ndim: int, metric_name: str, accuracy: str = 'f32') -> Callable:
+
+    try:
+        from numba import cfunc, types, carray
+    except ImportError:
+        raise ModuleNotFoundError(
+            'To use JIT install Numba with `pip install numba`.'
+            'Alternatively, reinstall usearch with `pip install usearch[jit]`')
+
+    # Showcases how to use Numba to JIT-compile similarity measures for USearch.
+    # https://numba.readthedocs.io/en/stable/reference/jit-compilation.html#c-callbacks
+
+    if accuracy == 'f32':
+        signature = types.float32(
+            types.CPointer(types.float32),
+            types.CPointer(types.float32),
+            types.size_t, types.size_t)
+
+        if metric_name == 'ip':
+
+            def numba_ip(a, b, _n, _m):
+                a_array = carray(a, ndim)
+                b_array = carray(b, ndim)
+                ab = 0.0
+                for i in range(ndim):
+                    ab += a_array[i] * b_array[i]
+                return ab
+
+            return cfunc(numba_ip, signature)
+
+        if metric_name == 'cos':
+
+            def numba_cos(a, b, _n, _m):
+                a_array = carray(a, ndim)
+                b_array = carray(b, ndim)
+                ab = 0.0
+                a_sq = 0.0
+                b_sq = 0.0
+                for i in range(ndim):
+                    ab += a_array[i] * b_array[i]
+                    a_sq += a_array[i] * a_array[i]
+                    b_sq += b_array[i] * b_array[i]
+                return ab / (sqrt(a_sq) * sqrt(b_sq))
+
+            return cfunc(numba_cos, signature)
+
+        if metric_name == 'l2sq':
+
+            def numba_l2sq(a, b, _n, _m):
+                a_array = carray(a, ndim)
+                b_array = carray(b, ndim)
+                ab_delta_sq = 0.0
+                for i in range(ndim):
+                    ab_delta_sq += (a_array[i] - b_array[i]) * \
+                        (a_array[i] - b_array[i])
+                return ab_delta_sq
+
+            return cfunc(numba_l2sq, signature)
+
+    return None
+
+
+class Index:
+    """Fast JIT-compiled index for equi-dimensional embeddings.
+
+    Vector labels must be integers.
+    Vectors must have the same number of dimensions within the index.
+    Supports Inner Product, Cosine Distance, Ln measures
+    like the Euclidean metric, as well as automatic downcasting
+    and quantization.
+    """
+
+    def __init__(
+        self,
+        ndim: int,
+        dtype: str = 'f32',
+        metric: Union[str, int] = 'ip',
+        jit: bool = False,
+
+        connectivity: int = DEFAULT_CONNECTIVITY,
+        expansion_add: int = DEFAULT_EXPANSION_ADD,
+        expansion_search: int = DEFAULT_EXPANSION_SEARCH,
+        tune: bool = False,
+
+        path: Optional[os.PathLike] = None,
+        view: bool = False,
+    ) -> None:
+        """Construct the index and compiles the functions, if requested (expensive).
+
+        :param ndim: Number of vector dimensions
+        :type ndim: int
+        :param dtype: Scalar type for vectors, defaults to 'f32'
+        :type dtype: str, optional
+            Example: you can use the `f16` index with `f32` vectors,
+            which will be automatically downcasted.
+
+        :param metric: Distance function, defaults to 'ip'
+        :type metric: Union[str, int], optional
+            Name of distance function, or the address of the
+            Numba `cfunc` JIT-compiled object.
+
+        :param jit: Enable Numba to JIT compile the metric, defaults to False
+        :type jit: bool, optional
+            This can result in up-to 3x performance difference on very large vectors
+            and very recent hardware, as the Python module is compiled with high
+            compatibility in mind and avoids very fancy assembly instructions.
+
+        :param connectivity: Connections per node in HNSW, defaults to None
+        :type connectivity: Optional[int], optional
+            Hyper-parameter for the number of Graph connections
+            per layer of HNSW. The original paper calls it "M".
+            Optional, but can't be changed after construction.
+
+        :param expansion_add: Traversal depth on insertions, defaults to None
+        :type expansion_add: Optional[int], optional
+            Hyper-parameter for the search depth when inserting new
+            vectors. The original paper calls it "efConstruction".
+            Can be changed afterwards, as the `.expansion_add`.
+
+        :param expansion_search: Traversal depth on queries, defaults to None
+        :type expansion_search: Optional[int], optional
+            Hyper-parameter for the search depth when querying 
+            nearest neighbors. The original paper calls it "ef".
+            Can be changed afterwards, as the `.expansion_search`.
+
+        :param tune: Automatically adjusts hyper-parameters, defaults to False
+        :type tune: bool, optional
+
+        :param path: Where to store the index, defaults to None
+        :type path: Optional[os.PathLike], optional
+        :param view: Are we simply viewing an immutable index, defaults to False
+        :type view: bool, optional
+        """
+        if jit:
+            assert isinstance(metric, str), 'Name the metric to JIT'
+            self._metric_name = metric
+            self._metric_jit = jit_metric(
+                ndim=ndim,
+                metric_name=metric,
+                dtype=dtype,
+            )
+            self._metric_pointer = self._metric_jit.address if \
+                self._metric_jit else 0
+
+        elif isinstance(metric, int):
+            self._metric_name = ''
+            self._metric_jit = None
+            self._metric_pointer = metric
+
+        else:
+            if metric is None:
+                metric = 'ip'
+            assert isinstance(metric, str)
+            self._metric_name = metric
+            self._metric_jit = None
+            self._metric_pointer = 0
+
+        self._compiled = _CompiledIndex(
+            ndim=ndim,
+            metric=self._metric_name,
+            metric_pointer=self._metric_pointer,
+            dtype=dtype,
+            connectivity=connectivity,
+            expansion_add=expansion_add,
+            expansion_search=expansion_search,
+            tune=tune,
+        )
+
+        self.path = path
+        if path and os.path.exists(path):
+            if view:
+                self._compiled.view(path)
+            else:
+                self._compiled.load(path)
+
+    def add(
+            self, labels, vectors, *,
+            copy: bool = True, threads: int = 0):
+        """Inserts one or move vectors into the index.
+
+        For maximal performance the `labels` and `vectors`
+        should conform to the Python's "buffer protocol" spec.
+
+        To index a single entry: 
+            labels: int, vectors: np.ndarray.
+        To index many entries: 
+            labels: np.ndarray, vectors: np.ndarray.
+
+        When working with extremely large indexes, you may want to
+        pass `copy=False`, if you can guarantee the lifetime of the
+        primary vectors store during the process of construction.
+
+        :param labels: Unique identifier for passed vectors.
+        :type labels: Buffer
+        :param vectors: Collection of vectors.
+        :type vectors: Buffer
+        :param copy: Should the index store a copy of vectors, defaults to True
+        :type copy: bool, optional
+        :param threads: Optimal number of cores to use, defaults to 0
+        :type threads: int, optional
+        """
+        if isinstance(labels, np.ndarray):
+            labels = labels.astype(np.longlong)
+        self._compiled.add(labels, vectors, copy=copy, threads=threads)
+
+    def search(
+            self, vectors, k: int = 10, *,
+            threads: int = 0, exact: bool = False) -> Triplet:
+        return self._compiled.search(vectors, k, exact=exact, threads=threads)
+
+    def __len__(self) -> int:
+        return len(self._compiled)
+
+    @property
+    def size(self) -> int:
+        return self._compiled.size
+
+    @property
+    def ndim(self) -> int:
+        return self._compiled.ndim
+
+    @property
+    def dtype(self) -> str:
+        return self._compiled.dtype
+
+    @property
+    def connectivity(self) -> int:
+        return self._compiled.connectivity
+
+    @property
+    def capacity(self) -> int:
+        return self._compiled.capacity
+
+    @property
+    def memory_usage(self) -> int:
+        return self._compiled.memory_usage
+
+    @property
+    def expansion_add(self) -> int:
+        return self._compiled.expansion_add
+
+    @property
+    def expansion_search(self) -> int:
+        return self._compiled.expansion_search
+
+    @expansion_add.setter
+    def change_expansion_add(self, v: int):
+        self._compiled.expansion_add = v
+
+    @expansion_search.setter
+    def change_expansion_search(self, v: int):
+        self._compiled.expansion_search = v
+
+    def save(self, path: os.PathLike):
+        self._compiled.save(path)
+
+    def load(self, path: os.PathLike):
+        self._compiled.load(path)
+
+    def view(self, path: os.PathLike):
+        self._compiled.view(path)
+
+    def clear(self):
+        self._compiled.clear()
+
+    def remove(self, label: int):
+        pass
diff --git a/robin-map b/robin-map
new file mode 160000
index 00000000..851a59e0
--- /dev/null
+++ b/robin-map
@@ -0,0 +1,1 @@
+Subproject commit 851a59e0e3063ee0e23089062090a73fd3de482d
diff --git a/setup.py b/setup.py
index a866c24f..3a87258f 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@
 
 ext_modules = [
     Pybind11Extension(
-        'usearch.index',
+        'usearch.compiled',
         ['python/lib.cpp'],
         extra_compile_args=compile_args,
         extra_link_args=link_args,
@@ -78,6 +78,8 @@
         'Topic :: Scientific/Engineering :: Artificial Intelligence',
     ],
 
-    include_dirs=['include', 'fp16/include', 'simsimd/include', 'src'],
+    include_dirs=[
+        'include', 'src',
+        'fp16/include', 'robin-map/include', 'simsimd/include'],
     ext_modules=ext_modules,
 )
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f7ec48f6..1592e8c7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -69,6 +69,7 @@ include(clipp)
 set(USEARCH_PUNNED_INCLUDE_DIRS
     "${CMAKE_CURRENT_SOURCE_DIR}/../include"
     "${CMAKE_CURRENT_SOURCE_DIR}/../fp16/include"
+    "${CMAKE_CURRENT_SOURCE_DIR}/../robin-map/include"
     "${CMAKE_CURRENT_SOURCE_DIR}/../simsimd/include"
     "${CMAKE_CURRENT_SOURCE_DIR}/"
 )
diff --git a/src/punned.hpp b/src/punned.hpp
index 2c293921..4fabd389 100644
--- a/src/punned.hpp
+++ b/src/punned.hpp
@@ -1,13 +1,15 @@
 #pragma once
 #include <stdlib.h> // `aligned_alloc`
 
-#include <functional> // `std::function`
-#include <numeric>    // `std::iota`
-#include <stdexcept>  // `std::invalid_argument`
-#include <thread>     // `std::thread`
-#include <vector>     // `std::vector`
+#include <functional>   // `std::function`
+#include <numeric>      // `std::iota`
+#include <shared_mutex> // `std::shared_mutex`
+#include <stdexcept>    // `std::invalid_argument`
+#include <thread>       // `std::thread`
+#include <vector>       // `std::vector`
 
 #include <fp16/fp16.h>
+#include <tsl/robin_map.h>
 
 #include <usearch/usearch.hpp>
 
@@ -401,6 +403,8 @@ class punned_gt {
 
     using member_iterator_t = typename index_t::member_iterator_t;
     using member_citerator_t = typename index_t::member_citerator_t;
+    using member_ref_t = typename index_t::member_ref_t;
+    using member_cref_t = typename index_t::member_cref_t;
 
     std::size_t dimensions_ = 0;
     std::size_t casted_vector_bytes_ = 0;
@@ -414,6 +418,10 @@ class punned_gt {
         cast_t from_f16{};
         cast_t from_f32{};
         cast_t from_f64{};
+        cast_t to_f8{};
+        cast_t to_f16{};
+        cast_t to_f32{};
+        cast_t to_f64{};
     } casts_;
 
     punned_stateful_metric_t root_metric_;
@@ -421,6 +429,13 @@ class punned_gt {
     mutable std::vector<std::size_t> available_threads_;
     mutable std::mutex available_threads_mutex_;
 
+    using shared_mutex_t = std::mutex; // TODO: Find an OS-compatible solution
+    using shared_lock_t = std::unique_lock<shared_mutex_t>;
+    using unique_lock_t = std::unique_lock<shared_mutex_t>;
+
+    mutable shared_mutex_t lookup_table_mutex_;
+    tsl::robin_map<label_t, id_t> lookup_table_;
+
   public:
     using search_results_t = typename index_t::search_results_t;
     using add_result_t = typename index_t::add_result_t;
@@ -511,6 +526,11 @@ class punned_gt {
     search_results_t search_around(label_t hint, f32_t const* vector, std::size_t wanted, search_config_t config) const { return search_around_(hint, vector, wanted, config, casts_.from_f32); }
     search_results_t search_around(label_t hint, f64_t const* vector, std::size_t wanted, search_config_t config) const { return search_around_(hint, vector, wanted, config, casts_.from_f64); }
 
+    void reconstruct(label_t label, f8_bits_t* vector) const { return reconstruct_(label, vector, casts_.to_f8); }
+    void reconstruct(label_t label, f16_bits_t* vector) const { return reconstruct_(label, vector, casts_.to_f16); }
+    void reconstruct(label_t label, f32_t* vector) const { return reconstruct_(label, vector, casts_.to_f32); }
+    void reconstruct(label_t label, f64_t* vector) const { return reconstruct_(label, vector, casts_.to_f64); }
+
     static punned_gt ip(std::size_t dimensions, accuracy_t accuracy = accuracy_t::f16_k, config_t config = {}) { return make_(dimensions, accuracy, ip_metric_(dimensions, accuracy), make_casts_(accuracy), config); }
     static punned_gt l2sq(std::size_t dimensions, accuracy_t accuracy = accuracy_t::f16_k, config_t config = {}) { return make_(dimensions, accuracy, l2_metric_(dimensions, accuracy), make_casts_(accuracy), config); }
     static punned_gt cos(std::size_t dimensions, accuracy_t accuracy = accuracy_t::f32_k, config_t config = {}) { return make_(dimensions, accuracy, cos_metric_(dimensions, accuracy), make_casts_(accuracy), config); }
@@ -589,7 +609,12 @@ class punned_gt {
         if (casted)
             vector_data = casted_data, vector_bytes = casted_vector_bytes_, config.store_vector = true;
 
-        return typed_->add(label, {vector_data, vector_bytes}, config);
+        add_result_t result = typed_->add(label, {vector_data, vector_bytes}, config);
+        {
+            unique_lock_t lock(lookup_table_mutex_);
+            lookup_table_.emplace(label, result.id);
+        }
+        return result;
     }
 
     template <typename scalar_at>
@@ -624,6 +649,21 @@ class punned_gt {
         return typed_->search_around(static_cast<id_t>(hint), {vector_data, vector_bytes}, wanted, config);
     }
 
+    id_t lookup_id_(label_t label) const {
+        shared_lock_t lock(lookup_table_mutex_);
+        return lookup_table_.at(label);
+    }
+
+    template <typename scalar_at> void reconstruct_(label_t label, scalar_at* reconstructed, cast_t const& cast) const {
+        id_t id = lookup_id_(label);
+        member_citerator_t iterator = typed_->cbegin() + id;
+        member_cref_t member = *iterator;
+        byte_t const* casted_vector = reinterpret_cast<byte_t const*>(member.vector.data());
+        bool casted = cast(casted_vector, casted_vector_bytes_, (byte_t*)reconstructed);
+        if (!casted)
+            std::memcpy(reconstructed, casted_vector, casted_vector_bytes_);
+    }
+
     template <typename scalar_at> add_result_t add_(label_t label, scalar_at const* vector, cast_t const& cast) {
         thread_lock_t lock = thread_lock_();
         add_config_t add_config;
@@ -686,6 +726,10 @@ class punned_gt {
         result.from_f16 = cast_gt<f16_bits_t, to_scalar_at>{};
         result.from_f32 = cast_gt<f32_t, to_scalar_at>{};
         result.from_f64 = cast_gt<f64_t, to_scalar_at>{};
+        result.to_f8 = cast_gt<to_scalar_at, f8_bits_t>{};
+        result.to_f16 = cast_gt<to_scalar_at, f16_bits_t>{};
+        result.to_f32 = cast_gt<to_scalar_at, f32_t>{};
+        result.to_f64 = cast_gt<to_scalar_at, f64_t>{};
         return result;
     }
 


Test patch:
diff --git a/python/scripts/test.py b/python/scripts/test.py
index 618024b7..975831fb 100644
--- a/python/scripts/test.py
+++ b/python/scripts/test.py
@@ -86,7 +86,7 @@ def python_dot(a, b, n, m):
             c += a_array[i] * b_array[i]
         return c
 
-    index = Index(ndim=ndim, metric_pointer=python_dot.address)
+    index = Index(ndim=ndim, metric=python_dot.address)
 
     vectors = np.random.uniform(
         0, 0.3, (size, index.ndim)).astype(np.float32)
diff --git a/src/test.cpp b/src/test.cpp
index 70f85809..fe2d8eb7 100644
--- a/src/test.cpp
+++ b/src/test.cpp
@@ -12,7 +12,7 @@ using namespace unum;
 using point_id_t = std::int64_t;
 
 template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
-    using span_t = span_gt<scalar_at const>;
+    using view_t = span_gt<scalar_at const>;
     using distance_t = typename index_at::distance_t;
 
     scalar_at vec[3] = {10, 20, 15};
@@ -20,12 +20,12 @@ template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
     scalar_at vec_b[3] = {16, 17, 18};
 
     index.reserve(10);
-    index.add(42, span_t{&vec[0], 3ul});
+    index.add(42, view_t{&vec[0], 3ul});
 
     // Default approximate search
     point_id_t matched_labels[10] = {0};
     distance_t matched_distances[10] = {0};
-    std::size_t matched_count = index.search(span_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
+    std::size_t matched_count = index.search(view_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
 
     assert(matched_count == 1);
     assert(matched_labels[0] == 42);
@@ -34,12 +34,12 @@ template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
     // Add more entries
     search_config_t search_config;
     search_config.exact = true;
-    index.add(43, span_t{&vec_a[0], 3ul});
-    index.add(44, span_t{&vec_b[0], 3ul});
+    index.add(43, view_t{&vec_a[0], 3ul});
+    index.add(44, view_t{&vec_b[0], 3ul});
     assert(index.size() == 3);
 
     // Perform exact search
-    matched_count = index.search(span_t{&vec[0], 3ul}, 5, search_config).dump_to(matched_labels, matched_distances);
+    matched_count = index.search(view_t{&vec[0], 3ul}, 5, search_config).dump_to(matched_labels, matched_distances);
 
     // Validate scans
     std::size_t count = 0;
@@ -54,14 +54,14 @@ template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
     // Search again over reconstructed index
     index.save("tmp.usearch");
     index.load("tmp.usearch");
-    matched_count = index.search(span_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
+    matched_count = index.search(view_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
     assert(matched_count == 3);
     assert(matched_labels[0] == 42);
     assert(std::abs(matched_distances[0]) < 0.01);
 
     // Search again over mapped index
     index.view("tmp.usearch");
-    matched_count = index.search(span_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
+    matched_count = index.search(view_t{&vec[0], 3ul}, 5).dump_to(matched_labels, matched_distances);
     assert(matched_count == 3);
     assert(matched_labels[0] == 42);
     assert(std::abs(matched_distances[0]) < 0.01);
@@ -70,6 +70,24 @@ template <typename scalar_at, typename index_at> void test3d(index_at&& index) {
     assert(index.stats().max_edges > 0);
 }
 
+template <typename scalar_at, typename index_at> void test3d_punned(index_at&& index) {
+    using view_t = span_gt<scalar_at const>;
+    using span_t = span_gt<scalar_at>;
+    using distance_t = typename index_at::distance_t;
+
+    scalar_at vec[3] = {10, 20, 15};
+
+    index.reserve(10);
+    index.add(42, view_t{&vec[0], 3ul});
+
+    // Reconstruct
+    scalar_at vec_reconstructed[3] = {0, 0, 0};
+    index.reconstruct(42, span_t{&vec_reconstructed[0], 3ul});
+    assert(vec_reconstructed[0] == vec[0]);
+    assert(vec_reconstructed[1] == vec[1]);
+    assert(vec_reconstructed[2] == vec[2]);
+}
+
 int main(int, char**) {
 
     test3d<float>(index_gt<cos_gt<float>, point_id_t, std::uint32_t, float>{});
@@ -84,5 +102,8 @@ int main(int, char**) {
     test3d<double>(punned_small_t::cos(3));
     test3d<double>(punned_small_t::l2sq(3));
 
+    test3d_punned<float>(punned_small_t::cos(3));
+    test3d_punned<float>(punned_small_t::l2sq(3));
+
     return 0;
 }
\ No newline at end of file