deglib 0.2.4__tar.gz → 0.2.6__tar.gz
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.
- {deglib-0.2.4 → deglib-0.2.6}/CMakeLists.txt +11 -2
- {deglib-0.2.4/src/deglib.egg-info → deglib-0.2.6}/PKG-INFO +16 -5
- {deglib-0.2.4 → deglib-0.2.6}/README.md +15 -4
- {deglib-0.2.4 → deglib-0.2.6}/lib/CMakeLists.txt +4 -5
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/build.h +3 -1
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/builder.h +101 -2
- deglib-0.2.6/lib/deglib/include/deglib/deglib.h +118 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/fp16_ip.h +30 -2
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/fp16_l2.h +32 -1
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/fp32_ip.h +53 -16
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/fp32_l2.h +52 -16
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/int8_ip.h +76 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/int8_l2.h +28 -18
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/uint8_ip.h +84 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/uint8_l2.h +28 -18
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph/dynamic_graph.h +12 -96
- deglib-0.2.6/lib/deglib/include/deglib/graph/internal_graph.h +912 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph/readonly_graph.h +69 -111
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph/sizebounded_graph.h +44 -176
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph.h +12 -46
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/flas/junker_volgenant_solver.h +4 -2
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/quantization/evp_quantize.h +96 -0
- deglib-0.2.6/lib/deglib/include/deglib/optimization/quantization/quantizer_concept.h +41 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/quantization/scalar_quantize.h +137 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization.h +6 -23
- deglib-0.2.6/lib/deglib/include/deglib/search/kmeans.h +428 -0
- deglib-0.2.6/lib/deglib/include/deglib/search/result_list.h +240 -0
- deglib-0.2.6/lib/deglib/include/deglib/search/searcher.h +902 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/search.h +13 -24
- {deglib-0.2.4 → deglib-0.2.6}/setup.py +28 -24
- {deglib-0.2.4 → deglib-0.2.6}/src/deg_cpp/deglib_cpp.cpp +120 -80
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/__init__.py +1 -3
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/graph.py +8 -13
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/optimization.py +5 -17
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/search.py +30 -5
- {deglib-0.2.4 → deglib-0.2.6/src/deglib.egg-info}/PKG-INFO +16 -5
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib.egg-info/SOURCES.txt +3 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_builder.py +75 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_graph.py +3 -7
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_searcher.py +65 -18
- deglib-0.2.4/lib/deglib/include/deglib/deglib.h +0 -17
- deglib-0.2.4/lib/deglib/include/deglib/graph/internal_graph.h +0 -528
- deglib-0.2.4/lib/deglib/include/deglib/search/searcher.h +0 -493
- {deglib-0.2.4 → deglib-0.2.6}/LICENSE +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/MANIFEST.in +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/CMakeLists.txt +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/benchmark.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/dataset.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/file_io.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/logging.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/repository.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/stats.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/bench/include/stopwatch.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/cmake_modules/DetectCPUFeatures.cmake +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/CMakeLists.txt +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/analysis.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/concurrent.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/config.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/evp_ip.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/fp16.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/fp32.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/int8.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/residual_mode.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distance/uint8.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/distances.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/filter.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph/intrusive_list.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph/mutable_graph.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/graph/visited_list_pool.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/flas/fast_linear_assignment_sorter.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/flas/fast_linear_assignment_sorter_mt.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/pruning.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/optimization/transform.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/utils/cpu.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/utils/memory.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/deglib/include/deglib/utils/random.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/test/CMakeLists.txt +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/lib/test/src/common/test_helpers.h +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/pyproject.toml +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/setup.cfg +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/analysis.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/builder.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/cpu.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/distances.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib/utils.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib.egg-info/dependency_links.txt +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib.egg-info/requires.txt +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/src/deglib.egg-info/top_level.txt +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_analysis.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_filter.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_presort.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_rerank.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_scalar_quantizer.py +0 -0
- {deglib-0.2.4 → deglib-0.2.6}/tests/test_transform.py +0 -0
|
@@ -15,11 +15,20 @@ find_package(pybind11 CONFIG REQUIRED)
|
|
|
15
15
|
set(ENABLE_BENCHMARKS OFF CACHE BOOL "Disable benchmarks" FORCE)
|
|
16
16
|
set(ENABLE_TESTING OFF CACHE BOOL "Disable tests" FORCE)
|
|
17
17
|
|
|
18
|
+
# Find deglib cpp source: prefer ../cpp in repository checkouts, fallback to local lib/ (PyPI sdist)
|
|
19
|
+
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../cpp/CMakeLists.txt")
|
|
20
|
+
set(DEGLIB_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../cpp")
|
|
21
|
+
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/CMakeLists.txt")
|
|
22
|
+
set(DEGLIB_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib")
|
|
23
|
+
else()
|
|
24
|
+
message(FATAL_ERROR "Could not find deglib cpp source directory (checked ../cpp/ and lib/)")
|
|
25
|
+
endif()
|
|
26
|
+
|
|
18
27
|
# Add cpp-deglib
|
|
19
|
-
add_subdirectory(${
|
|
28
|
+
add_subdirectory(${DEGLIB_CPP_DIR} deglib_cpp_build)
|
|
20
29
|
pybind11_add_module(deglib_cpp src/deg_cpp/deglib_cpp.cpp)
|
|
21
30
|
|
|
22
31
|
# Specify the include directories
|
|
23
|
-
include_directories(${
|
|
32
|
+
include_directories(${DEGLIB_CPP_DIR}/deglib/include)
|
|
24
33
|
|
|
25
34
|
target_link_libraries(deglib_cpp PRIVATE compile-options)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deglib
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Python bindings for the Dynamic Exploration Graph library by Nico Hezel
|
|
5
5
|
Author: Nico Hezel
|
|
6
6
|
Author-email: Bruno Schilling <bruno.schilling@htw-berlin.de>
|
|
@@ -278,10 +278,21 @@ Controls the topology optimization strategy:
|
|
|
278
278
|
- `OptimizationTarget.HighLID`: Optimized for datasets with high local intrinsic dimensionality (supports multithreaded building).
|
|
279
279
|
- `OptimizationTarget.StreamingData`: Optimized for continuous dynamic additions and deletions.
|
|
280
280
|
|
|
281
|
-
### Search Parameter `
|
|
282
|
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
281
|
+
### Unified Search Parameter: `eps_or_ef`
|
|
282
|
+
`Searcher` provides a unified exploration parameter `eps_or_ef`:
|
|
283
|
+
- **Relative Distance Margin (`eps_or_ef < 1.0`)**: Standard DEG dynamic distance exploration bound $(1 + \epsilon) \cdot d_{\text{cur}}$.
|
|
284
|
+
- Small values (e.g. `eps_or_ef=0.001` or `0.01`): Faster query execution.
|
|
285
|
+
- Higher values (e.g. `eps_or_ef=0.1` to `0.3`): Higher recall rate.
|
|
286
|
+
- **Fixed Candidate Pool (`eps_or_ef >= 1.0`)**: HNSW-style search with a fixed candidate pool size of `round(eps_or_ef)` during exploration.
|
|
287
|
+
- Typical values: `64`, `96`, `128`, `200`, `400`.
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
# Mode 1: Relative distance margin (default: eps_or_ef=0.1)
|
|
291
|
+
indices, distances = searcher.search(query, k=10, eps_or_ef=0.1)
|
|
292
|
+
|
|
293
|
+
# Mode 2: Fixed candidate pool (HNSW-style)
|
|
294
|
+
indices, distances = searcher.search(query, k=10, eps_or_ef=128)
|
|
295
|
+
```
|
|
285
296
|
|
|
286
297
|
### Supported Metrics & Data Types
|
|
287
298
|
- `Metric.FP32_L2`: Euclidean distance (`np.float32`)
|
|
@@ -250,10 +250,21 @@ Controls the topology optimization strategy:
|
|
|
250
250
|
- `OptimizationTarget.HighLID`: Optimized for datasets with high local intrinsic dimensionality (supports multithreaded building).
|
|
251
251
|
- `OptimizationTarget.StreamingData`: Optimized for continuous dynamic additions and deletions.
|
|
252
252
|
|
|
253
|
-
### Search Parameter `
|
|
254
|
-
|
|
255
|
-
-
|
|
256
|
-
-
|
|
253
|
+
### Unified Search Parameter: `eps_or_ef`
|
|
254
|
+
`Searcher` provides a unified exploration parameter `eps_or_ef`:
|
|
255
|
+
- **Relative Distance Margin (`eps_or_ef < 1.0`)**: Standard DEG dynamic distance exploration bound $(1 + \epsilon) \cdot d_{\text{cur}}$.
|
|
256
|
+
- Small values (e.g. `eps_or_ef=0.001` or `0.01`): Faster query execution.
|
|
257
|
+
- Higher values (e.g. `eps_or_ef=0.1` to `0.3`): Higher recall rate.
|
|
258
|
+
- **Fixed Candidate Pool (`eps_or_ef >= 1.0`)**: HNSW-style search with a fixed candidate pool size of `round(eps_or_ef)` during exploration.
|
|
259
|
+
- Typical values: `64`, `96`, `128`, `200`, `400`.
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
# Mode 1: Relative distance margin (default: eps_or_ef=0.1)
|
|
263
|
+
indices, distances = searcher.search(query, k=10, eps_or_ef=0.1)
|
|
264
|
+
|
|
265
|
+
# Mode 2: Fixed candidate pool (HNSW-style)
|
|
266
|
+
indices, distances = searcher.search(query, k=10, eps_or_ef=128)
|
|
267
|
+
```
|
|
257
268
|
|
|
258
269
|
### Supported Metrics & Data Types
|
|
259
270
|
- `Metric.FP32_L2`: Euclidean distance (`np.float32`)
|
|
@@ -70,12 +70,11 @@ else() # Native build
|
|
|
70
70
|
|
|
71
71
|
# setup compiler flags
|
|
72
72
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
73
|
+
# Portable native build: generic code is compiled for the build machine's
|
|
74
|
+
# baseline ISA only (no explicit AVX-512), so the module imports cleanly on
|
|
75
|
+
# CPUs without AVX-512. AVX-512 kernels are per-function target attributes
|
|
76
|
+
# (DEGLIB_TARGET_AVX512*), gated at runtime by deglib::cpu::select_dist().
|
|
73
77
|
target_compile_options(compile-options INTERFACE -O3 -march=native -fpic -w -pthread -ftree-vectorize)
|
|
74
|
-
if(SUPPORT_AVX512F)
|
|
75
|
-
target_compile_options(compile-options INTERFACE -mavx512f -mfma)
|
|
76
|
-
elseif(SUPPORT_AVX2)
|
|
77
|
-
target_compile_options(compile-options INTERFACE -mavx2 -mfma)
|
|
78
|
-
endif()
|
|
79
78
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
80
79
|
target_compile_options(compile-options INTERFACE -O2 -DNDEBUG -march=native -fpic)
|
|
81
80
|
elseif(MSVC)
|
|
@@ -41,7 +41,9 @@ inline deglib::graph::SizeBoundedGraph create_random_graph(
|
|
|
41
41
|
const uint32_t vertex_count = (max_size > 0 && max_size < repository.size()) ? max_size : uint32_t(repository.size());
|
|
42
42
|
const auto feature_data = repository.getFeature(0);
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
auto graph = deglib::graph::SizeBoundedGraph(vertex_count, k, feature_space);
|
|
45
|
+
deglib::builder::populate_random_graph(graph, feature_data, vertex_count);
|
|
46
|
+
return graph;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
inline void create_graph(
|
|
@@ -649,7 +649,7 @@ class EvenRegularGraphBuilder {
|
|
|
649
649
|
const auto dist_func_param = graph.getFeatureSpace().get_dist_func_param();
|
|
650
650
|
|
|
651
651
|
// find good neighbors for the new vertex
|
|
652
|
-
const
|
|
652
|
+
const auto entry_vertex_indices = graph.getEntryVertexIndices();
|
|
653
653
|
auto top_list =
|
|
654
654
|
graph.search_intern(entry_vertex_indices, new_vertex_feature, std::max(uint32_t(this->extend_k_), edges_per_vertex), this->extend_eps_);
|
|
655
655
|
const auto results = topListAscending(top_list);
|
|
@@ -1535,7 +1535,7 @@ DynamicExplorationGraph build_from_data(
|
|
|
1535
1535
|
}
|
|
1536
1536
|
|
|
1537
1537
|
auto feature_space = deglib::distances::FloatSpace(dims, metric);
|
|
1538
|
-
auto graph = deglib::
|
|
1538
|
+
auto graph = DynamicExplorationGraph(std::make_unique<deglib::graph::SizeBoundedGraph>(vertex_count, edges_per_vertex, feature_space));
|
|
1539
1539
|
|
|
1540
1540
|
std::mt19937 rng(seed);
|
|
1541
1541
|
auto builder = EvenRegularGraphBuilder(
|
|
@@ -1555,4 +1555,103 @@ DynamicExplorationGraph build_from_data(
|
|
|
1555
1555
|
return graph;
|
|
1556
1556
|
}
|
|
1557
1557
|
|
|
1558
|
+
/**
|
|
1559
|
+
* Populate a MutableGraph with a random k-regular graph.
|
|
1560
|
+
*
|
|
1561
|
+
* @param graph The mutable graph instance to populate.
|
|
1562
|
+
* @param feature_data Pointer to contiguous feature data bytes.
|
|
1563
|
+
* @param vertex_count Number of vertices to insert.
|
|
1564
|
+
* @param seed Random seed for deterministic graph construction (default: 7).
|
|
1565
|
+
*/
|
|
1566
|
+
inline void populate_random_graph(
|
|
1567
|
+
deglib::graph::MutableGraph& graph,
|
|
1568
|
+
const std::byte* feature_data,
|
|
1569
|
+
const uint32_t vertex_count,
|
|
1570
|
+
const uint32_t seed = 7
|
|
1571
|
+
) {
|
|
1572
|
+
const auto& feature_space = graph.getFeatureSpace();
|
|
1573
|
+
const auto edges_per_vertex = graph.getEdgesPerVertex();
|
|
1574
|
+
const auto dist_func = feature_space.get_dist_func();
|
|
1575
|
+
const auto dist_func_param = feature_space.get_dist_func_param();
|
|
1576
|
+
|
|
1577
|
+
// add the initial vertices (edges_per_vertex + 1)
|
|
1578
|
+
{
|
|
1579
|
+
const auto size = static_cast<uint32_t>(edges_per_vertex + 1);
|
|
1580
|
+
for (uint32_t y = 0; y < size; y++) {
|
|
1581
|
+
const auto query = feature_data + size_t(y) * feature_space.get_data_size();
|
|
1582
|
+
const auto internal_index = graph.addVertex(y, query);
|
|
1583
|
+
|
|
1584
|
+
auto neighbor_indices = std::vector<uint32_t>();
|
|
1585
|
+
auto neighbor_weights = std::vector<float>();
|
|
1586
|
+
for (uint32_t x = 0; x < size; x++) {
|
|
1587
|
+
if (x == internal_index) continue;
|
|
1588
|
+
neighbor_indices.emplace_back(x);
|
|
1589
|
+
neighbor_weights.emplace_back(dist_func(query, feature_data + size_t(x) * feature_space.get_data_size(), dist_func_param));
|
|
1590
|
+
}
|
|
1591
|
+
graph.changeEdges(internal_index, neighbor_indices.data(), neighbor_weights.data());
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// random order of vertices
|
|
1596
|
+
auto rnd = std::mt19937(seed);
|
|
1597
|
+
auto rnd_neighbor = deglib::random::DeterministicUniformIntDistribution<uint32_t>(0, edges_per_vertex - 1);
|
|
1598
|
+
|
|
1599
|
+
// add the remaining vertices
|
|
1600
|
+
for (uint32_t label = edges_per_vertex + 1; label < vertex_count; label++) {
|
|
1601
|
+
const auto new_vertex_feature = feature_data + size_t(label) * feature_space.get_data_size();
|
|
1602
|
+
const auto internal_index = graph.addVertex(label, new_vertex_feature);
|
|
1603
|
+
auto top_list = deglib::random::DeterministicUniformIntDistribution<uint32_t>(0, label - 1);
|
|
1604
|
+
|
|
1605
|
+
// remove the worst edge of the good neighbors and connect them with this new vertex
|
|
1606
|
+
auto new_neighbors = std::vector<std::pair<uint32_t, float>>();
|
|
1607
|
+
while (new_neighbors.size() < edges_per_vertex) {
|
|
1608
|
+
const auto candidate_index = static_cast<uint32_t>(top_list(rnd));
|
|
1609
|
+
|
|
1610
|
+
// check if the vertex is already in the edge list of the new vertex (added during a previous loop-run)
|
|
1611
|
+
// since all edges are undirected and the edge information of the new vertex does not yet exist, we search the other way around.
|
|
1612
|
+
if (graph.hasEdge(candidate_index, internal_index)) continue;
|
|
1613
|
+
|
|
1614
|
+
// find a new random neighbor
|
|
1615
|
+
uint32_t new_neighbor_index = 0;
|
|
1616
|
+
float new_neighbor_weight = 0;
|
|
1617
|
+
bool found = false;
|
|
1618
|
+
const auto neighbor_weights = graph.getNeighborWeights(candidate_index);
|
|
1619
|
+
const auto neighbor_indices = graph.getNeighborIndices(candidate_index);
|
|
1620
|
+
while (!found) {
|
|
1621
|
+
const auto edge_idx = static_cast<uint32_t>(rnd_neighbor(rnd));
|
|
1622
|
+
const auto neighbor_index = neighbor_indices[edge_idx];
|
|
1623
|
+
const auto neighbor_weight = neighbor_weights[edge_idx];
|
|
1624
|
+
|
|
1625
|
+
// the suggested neighbors might already be in the edge list of the new vertex
|
|
1626
|
+
if (!graph.hasEdge(neighbor_index, internal_index)) {
|
|
1627
|
+
new_neighbor_index = neighbor_index;
|
|
1628
|
+
new_neighbor_weight = neighbor_weight;
|
|
1629
|
+
found = true;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
// place the new vertex in the edge list of the result-vertex
|
|
1634
|
+
const auto candidate_dist = dist_func(new_vertex_feature, graph.getFeatureVector(candidate_index), dist_func_param);
|
|
1635
|
+
graph.changeEdge(candidate_index, new_neighbor_index, internal_index, candidate_dist);
|
|
1636
|
+
new_neighbors.emplace_back(candidate_index, candidate_dist);
|
|
1637
|
+
|
|
1638
|
+
// place the new vertex in the edge list of the worst edge neighbor
|
|
1639
|
+
const auto new_neighbor_dist = dist_func(new_vertex_feature, graph.getFeatureVector(new_neighbor_index), dist_func_param);
|
|
1640
|
+
graph.changeEdge(new_neighbor_index, candidate_index, internal_index, new_neighbor_dist);
|
|
1641
|
+
new_neighbors.emplace_back(new_neighbor_index, new_neighbor_dist);
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// sort the neighbors by their neighbor indices and store them in the new vertex
|
|
1645
|
+
std::sort(new_neighbors.begin(), new_neighbors.end(), [](const auto& x, const auto& y) { return x.first < y.first; });
|
|
1646
|
+
auto neighbor_indices = std::vector<uint32_t>();
|
|
1647
|
+
auto neighbor_weights = std::vector<float>();
|
|
1648
|
+
for (auto&& neighbor : new_neighbors) {
|
|
1649
|
+
neighbor_indices.emplace_back(neighbor.first);
|
|
1650
|
+
neighbor_weights.emplace_back(neighbor.second);
|
|
1651
|
+
}
|
|
1652
|
+
graph.changeEdges(internal_index, neighbor_indices.data(), neighbor_weights.data());
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1558
1656
|
} // end namespace deglib::builder
|
|
1657
|
+
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "deglib/analysis.h"
|
|
4
|
+
#include "deglib/builder.h"
|
|
5
|
+
#include "deglib/config.h"
|
|
6
|
+
#include "deglib/distances.h"
|
|
7
|
+
#include "deglib/filter.h"
|
|
8
|
+
#include "deglib/graph.h"
|
|
9
|
+
#include "deglib/optimization.h"
|
|
10
|
+
#include "deglib/search.h"
|
|
11
|
+
#include "deglib/search/searcher.h"
|
|
12
|
+
#include "deglib/utils/memory.h"
|
|
13
|
+
#include "deglib/utils/random.h"
|
|
14
|
+
|
|
15
|
+
namespace deglib {
|
|
16
|
+
using builder::build_from_data;
|
|
17
|
+
using builder::EvenRegularGraphBuilder;
|
|
18
|
+
using builder::OptimizationTarget;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create an EvenRegularGraphBuilder for building and incrementally modifying a DynamicExplorationGraph.
|
|
22
|
+
*/
|
|
23
|
+
inline builder::EvenRegularGraphBuilder create_builder(
|
|
24
|
+
DynamicExplorationGraph& graph,
|
|
25
|
+
std::mt19937& rnd,
|
|
26
|
+
const builder::OptimizationTarget optimization_target = builder::OptimizationTarget::LowLID,
|
|
27
|
+
const uint8_t extend_k = 0,
|
|
28
|
+
const float extend_eps = 0.1f,
|
|
29
|
+
const uint8_t improve_k = 0,
|
|
30
|
+
const float improve_eps = 0.001f,
|
|
31
|
+
const uint8_t max_path_length = 5,
|
|
32
|
+
const uint32_t improve_tries = 0
|
|
33
|
+
) {
|
|
34
|
+
return builder::EvenRegularGraphBuilder(
|
|
35
|
+
graph, rnd, optimization_target, extend_k, extend_eps, improve_k, improve_eps, max_path_length, improve_tries
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create an empty mutable DynamicExplorationGraph with the given capacity,
|
|
41
|
+
* edges per vertex, and feature space (backed by SizeBoundedGraph).
|
|
42
|
+
*/
|
|
43
|
+
inline DynamicExplorationGraph create_empty(
|
|
44
|
+
const uint32_t max_vertex_count,
|
|
45
|
+
const uint8_t edges_per_vertex,
|
|
46
|
+
const deglib::distances::FloatSpace& feature_space
|
|
47
|
+
) {
|
|
48
|
+
auto graph = std::make_unique<deglib::graph::SizeBoundedGraph>(max_vertex_count, edges_per_vertex, feature_space);
|
|
49
|
+
return DynamicExplorationGraph(std::move(graph));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create an empty mutable DynamicExplorationGraph with chunk-based dynamic memory allocation (backed by DynamicGraph).
|
|
54
|
+
*
|
|
55
|
+
* @param edges_per_vertex Number of edges per vertex (must be even).
|
|
56
|
+
* @param feature_space The feature space defining dimensionality and metric.
|
|
57
|
+
* @param chunk_size Target number of vertices per memory chunk (default = 1024).
|
|
58
|
+
* Will be automatically rounded up to the nearest power of 2 (e.g. 600 -> 1024).
|
|
59
|
+
*/
|
|
60
|
+
inline DynamicExplorationGraph create_dynamic_empty(
|
|
61
|
+
const uint8_t edges_per_vertex,
|
|
62
|
+
const deglib::distances::FloatSpace& feature_space,
|
|
63
|
+
const uint32_t chunk_size = 1024
|
|
64
|
+
) {
|
|
65
|
+
auto graph = std::make_unique<deglib::graph::DynamicGraph>(edges_per_vertex, feature_space, chunk_size);
|
|
66
|
+
return DynamicExplorationGraph(std::move(graph));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create a random exploration graph from the given feature data (backed by SizeBoundedGraph).
|
|
71
|
+
*
|
|
72
|
+
* @param feature_data Pointer to a contiguous array of feature vectors.
|
|
73
|
+
* Each vector is feature_space.get_data_size() bytes.
|
|
74
|
+
* @param vertex_count Number of vertices to insert.
|
|
75
|
+
* @param edges_per_vertex Number of edges per vertex (must be even).
|
|
76
|
+
* @param feature_space The feature space defining dimensionality and metric.
|
|
77
|
+
* @param seed Random seed for deterministic graph construction.
|
|
78
|
+
* @return A new DynamicExplorationGraph wrapping the created random graph.
|
|
79
|
+
*/
|
|
80
|
+
inline DynamicExplorationGraph create_random_graph(
|
|
81
|
+
const std::byte* feature_data,
|
|
82
|
+
const uint32_t vertex_count,
|
|
83
|
+
const uint8_t edges_per_vertex,
|
|
84
|
+
const deglib::distances::FloatSpace& feature_space,
|
|
85
|
+
const uint32_t seed = 7
|
|
86
|
+
) {
|
|
87
|
+
auto graph = std::make_unique<deglib::graph::SizeBoundedGraph>(vertex_count, edges_per_vertex, feature_space);
|
|
88
|
+
deglib::builder::populate_random_graph(*graph, feature_data, vertex_count, seed);
|
|
89
|
+
return DynamicExplorationGraph(std::move(graph));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Load a saved graph from disk as a compact, immutable DynamicExplorationGraph (backed by ReadOnlyGraph).
|
|
94
|
+
*/
|
|
95
|
+
inline DynamicExplorationGraph load_readonly_graph(const char* path_graph) {
|
|
96
|
+
auto graph = std::make_unique<deglib::graph::ReadOnlyGraph>(deglib::graph::load_readonly_graph(path_graph));
|
|
97
|
+
return DynamicExplorationGraph(std::move(graph));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Load a saved graph from disk as a chunk-allocated mutable DynamicExplorationGraph (backed by DynamicGraph).
|
|
102
|
+
*/
|
|
103
|
+
inline DynamicExplorationGraph load_dynamic_graph(const char* path_graph, const uint32_t chunk_size = 1024) {
|
|
104
|
+
auto graph = std::make_unique<deglib::graph::DynamicGraph>(deglib::graph::load_dynamic_graph(path_graph, chunk_size));
|
|
105
|
+
return DynamicExplorationGraph(std::move(graph));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Load a saved graph from disk as a fixed-capacity mutable DynamicExplorationGraph (backed by SizeBoundedGraph).
|
|
110
|
+
*
|
|
111
|
+
* @param new_max_size Optional capacity override. If 0, uses the graph's serialized size.
|
|
112
|
+
*/
|
|
113
|
+
inline DynamicExplorationGraph load_mutable_graph(const char* path_graph, const uint32_t new_max_size = 0) {
|
|
114
|
+
auto graph = std::make_unique<deglib::graph::SizeBoundedGraph>(deglib::graph::load_sizebounded_graph(path_graph, new_max_size));
|
|
115
|
+
return DynamicExplorationGraph(std::move(graph));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
} // namespace deglib
|
|
@@ -110,8 +110,26 @@ class InnerProductFP16_AVX512 {
|
|
|
110
110
|
__m512 sum512 = _mm512_add_ps(sum512_1, sum512_2);
|
|
111
111
|
float result = fp16_hsum512(sum512);
|
|
112
112
|
|
|
113
|
-
//
|
|
113
|
+
// Vectorized residual tail for arbitrary dimensions
|
|
114
114
|
if constexpr (HasTail) {
|
|
115
|
+
if ((last - a) >= 8) {
|
|
116
|
+
__m256 va8 = _mm256_cvtph_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(a)));
|
|
117
|
+
__m256 vb8 = _mm256_cvtph_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(b)));
|
|
118
|
+
__m256 prod8 = _mm256_mul_ps(va8, vb8);
|
|
119
|
+
result += fp16_hsum256(prod8);
|
|
120
|
+
a += 8;
|
|
121
|
+
b += 8;
|
|
122
|
+
}
|
|
123
|
+
if ((last - a) >= 4) {
|
|
124
|
+
__m128 va4 = _mm_cvtph_ps(_mm_loadu_si64(a));
|
|
125
|
+
__m128 vb4 = _mm_cvtph_ps(_mm_loadu_si64(b));
|
|
126
|
+
__m128 prod4 = _mm_mul_ps(va4, vb4);
|
|
127
|
+
prod4 = _mm_add_ps(prod4, _mm_movehl_ps(prod4, prod4));
|
|
128
|
+
prod4 = _mm_add_ss(prod4, _mm_shuffle_ps(prod4, prod4, 1));
|
|
129
|
+
result += _mm_cvtss_f32(prod4);
|
|
130
|
+
a += 4;
|
|
131
|
+
b += 4;
|
|
132
|
+
}
|
|
115
133
|
while (a < last) {
|
|
116
134
|
float fa = deglib::distances::fp16::fp16_to_float(*a++);
|
|
117
135
|
float fb = deglib::distances::fp16::fp16_to_float(*b++);
|
|
@@ -243,8 +261,18 @@ class InnerProductFP16_AVX2 {
|
|
|
243
261
|
__m256 sum256 = _mm256_add_ps(sum256_1, sum256_2);
|
|
244
262
|
float result = fp16_hsum256(sum256);
|
|
245
263
|
|
|
246
|
-
//
|
|
264
|
+
// Vectorized residual tail for arbitrary dimensions
|
|
247
265
|
if constexpr (HasTail) {
|
|
266
|
+
if ((last - a) >= 4) {
|
|
267
|
+
__m128 va4 = _mm_cvtph_ps(_mm_loadu_si64(a));
|
|
268
|
+
__m128 vb4 = _mm_cvtph_ps(_mm_loadu_si64(b));
|
|
269
|
+
__m128 prod4 = _mm_mul_ps(va4, vb4);
|
|
270
|
+
prod4 = _mm_add_ps(prod4, _mm_movehl_ps(prod4, prod4));
|
|
271
|
+
prod4 = _mm_add_ss(prod4, _mm_shuffle_ps(prod4, prod4, 1));
|
|
272
|
+
result += _mm_cvtss_f32(prod4);
|
|
273
|
+
a += 4;
|
|
274
|
+
b += 4;
|
|
275
|
+
}
|
|
248
276
|
while (a < last) {
|
|
249
277
|
float fa = deglib::distances::fp16::fp16_to_float(*a++);
|
|
250
278
|
float fb = deglib::distances::fp16::fp16_to_float(*b++);
|
|
@@ -115,7 +115,27 @@ class L2FP16_AVX512 {
|
|
|
115
115
|
float result = fp16_l2_hsum512(sum512);
|
|
116
116
|
|
|
117
117
|
// Scalar residual for the unaligned tail — eliminated at compile-time if HasTail == false
|
|
118
|
+
// Vectorized residual tail for arbitrary dimensions
|
|
118
119
|
if constexpr (HasTail) {
|
|
120
|
+
if ((last - a) >= 8) {
|
|
121
|
+
__m256 va8 = _mm256_cvtph_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(a)));
|
|
122
|
+
__m256 vb8 = _mm256_cvtph_ps(_mm_loadu_si128(reinterpret_cast<const __m128i*>(b)));
|
|
123
|
+
__m256 diff8 = _mm256_sub_ps(va8, vb8);
|
|
124
|
+
result += fp16_l2_hsum256(_mm256_mul_ps(diff8, diff8));
|
|
125
|
+
a += 8;
|
|
126
|
+
b += 8;
|
|
127
|
+
}
|
|
128
|
+
if ((last - a) >= 4) {
|
|
129
|
+
__m128 va4 = _mm_cvtph_ps(_mm_loadu_si64(a));
|
|
130
|
+
__m128 vb4 = _mm_cvtph_ps(_mm_loadu_si64(b));
|
|
131
|
+
__m128 diff4 = _mm_sub_ps(va4, vb4);
|
|
132
|
+
__m128 prod4 = _mm_mul_ps(diff4, diff4);
|
|
133
|
+
prod4 = _mm_add_ps(prod4, _mm_movehl_ps(prod4, prod4));
|
|
134
|
+
prod4 = _mm_add_ss(prod4, _mm_shuffle_ps(prod4, prod4, 1));
|
|
135
|
+
result += _mm_cvtss_f32(prod4);
|
|
136
|
+
a += 4;
|
|
137
|
+
b += 4;
|
|
138
|
+
}
|
|
119
139
|
while (a < last) {
|
|
120
140
|
float fa = deglib::distances::fp16::fp16_to_float(*a++);
|
|
121
141
|
float fb = deglib::distances::fp16::fp16_to_float(*b++);
|
|
@@ -251,8 +271,19 @@ class L2FP16_AVX2 {
|
|
|
251
271
|
__m256 sum256 = _mm256_add_ps(sum256_1, sum256_2);
|
|
252
272
|
float result = fp16_l2_hsum256(sum256);
|
|
253
273
|
|
|
254
|
-
//
|
|
274
|
+
// Vectorized residual tail for arbitrary dimensions
|
|
255
275
|
if constexpr (HasTail) {
|
|
276
|
+
if ((last - a) >= 4) {
|
|
277
|
+
__m128 va4 = _mm_cvtph_ps(_mm_loadu_si64(a));
|
|
278
|
+
__m128 vb4 = _mm_cvtph_ps(_mm_loadu_si64(b));
|
|
279
|
+
__m128 diff4 = _mm_sub_ps(va4, vb4);
|
|
280
|
+
__m128 prod4 = _mm_mul_ps(diff4, diff4);
|
|
281
|
+
prod4 = _mm_add_ps(prod4, _mm_movehl_ps(prod4, prod4));
|
|
282
|
+
prod4 = _mm_add_ss(prod4, _mm_shuffle_ps(prod4, prod4, 1));
|
|
283
|
+
result += _mm_cvtss_f32(prod4);
|
|
284
|
+
a += 4;
|
|
285
|
+
b += 4;
|
|
286
|
+
}
|
|
256
287
|
while (a < last) {
|
|
257
288
|
float fa = deglib::distances::fp16::fp16_to_float(*a++);
|
|
258
289
|
float fb = deglib::distances::fp16::fp16_to_float(*b++);
|
|
@@ -120,8 +120,29 @@ class InnerProductFloat_AVX512 {
|
|
|
120
120
|
_mm_store_ps(f, sum128);
|
|
121
121
|
float result = f[0] + f[1] + f[2] + f[3];
|
|
122
122
|
|
|
123
|
-
//
|
|
123
|
+
// Vectorized residual tail for arbitrary dimensions
|
|
124
124
|
if constexpr (HasTail) {
|
|
125
|
+
if ((last - a) >= 8) {
|
|
126
|
+
__m256 va8 = _mm256_loadu_ps(a);
|
|
127
|
+
__m256 vb8 = _mm256_loadu_ps(b);
|
|
128
|
+
__m256 prod8 = _mm256_mul_ps(va8, vb8);
|
|
129
|
+
__m128 sum128 = _mm_add_ps(_mm256_castps256_ps128(prod8), _mm256_extractf128_ps(prod8, 1));
|
|
130
|
+
alignas(16) float f[4];
|
|
131
|
+
_mm_store_ps(f, sum128);
|
|
132
|
+
result += f[0] + f[1] + f[2] + f[3];
|
|
133
|
+
a += 8;
|
|
134
|
+
b += 8;
|
|
135
|
+
}
|
|
136
|
+
if ((last - a) >= 4) {
|
|
137
|
+
__m128 va4 = _mm_loadu_ps(a);
|
|
138
|
+
__m128 vb4 = _mm_loadu_ps(b);
|
|
139
|
+
__m128 prod4 = _mm_mul_ps(va4, vb4);
|
|
140
|
+
prod4 = _mm_add_ps(prod4, _mm_movehl_ps(prod4, prod4));
|
|
141
|
+
prod4 = _mm_add_ss(prod4, _mm_shuffle_ps(prod4, prod4, 1));
|
|
142
|
+
result += _mm_cvtss_f32(prod4);
|
|
143
|
+
a += 4;
|
|
144
|
+
b += 4;
|
|
145
|
+
}
|
|
125
146
|
while (a < last) {
|
|
126
147
|
result = std::fma(*a++, *b++, result);
|
|
127
148
|
}
|
|
@@ -143,17 +164,20 @@ class InnerProductFloat_AVX512 {
|
|
|
143
164
|
}
|
|
144
165
|
|
|
145
166
|
if constexpr (HasDualSimd) {
|
|
146
|
-
const size_t
|
|
147
|
-
offset =
|
|
167
|
+
const size_t nc32 = dim / 32;
|
|
168
|
+
offset = nc32 * 32;
|
|
148
169
|
|
|
149
|
-
for (size_t c = 0; c <
|
|
150
|
-
size_t idx = c *
|
|
151
|
-
__m512
|
|
170
|
+
for (size_t c = 0; c < nc32; ++c) {
|
|
171
|
+
size_t idx = c * 32;
|
|
172
|
+
__m512 q_vec_lo = _mm512_loadu_ps(&query[idx]);
|
|
173
|
+
__m512 q_vec_hi = _mm512_loadu_ps(&query[idx + 16]);
|
|
152
174
|
|
|
153
175
|
for (size_t j = 0; j < BATCH_SIZE; ++j) {
|
|
154
176
|
const float* db_ = static_cast<const float*>(db[j]);
|
|
155
|
-
__m512
|
|
156
|
-
|
|
177
|
+
__m512 db_vec_lo = _mm512_loadu_ps(&db_[idx]);
|
|
178
|
+
__m512 db_vec_hi = _mm512_loadu_ps(&db_[idx + 16]);
|
|
179
|
+
s[j] = _mm512_fmadd_ps(q_vec_lo, db_vec_lo, s[j]);
|
|
180
|
+
s[j] = _mm512_fmadd_ps(q_vec_hi, db_vec_hi, s[j]);
|
|
157
181
|
}
|
|
158
182
|
}
|
|
159
183
|
}
|
|
@@ -242,8 +266,18 @@ class InnerProductFloat_AVX2 {
|
|
|
242
266
|
__m256 sum256 = _mm256_add_ps(sum256_1, sum256_2);
|
|
243
267
|
float result = fp32_hsum256(sum256);
|
|
244
268
|
|
|
245
|
-
//
|
|
269
|
+
// Vectorized residual tail for arbitrary dimensions
|
|
246
270
|
if constexpr (HasTail) {
|
|
271
|
+
if ((last - a) >= 4) {
|
|
272
|
+
__m128 va4 = _mm_loadu_ps(a);
|
|
273
|
+
__m128 vb4 = _mm_loadu_ps(b);
|
|
274
|
+
__m128 prod4 = _mm_mul_ps(va4, vb4);
|
|
275
|
+
prod4 = _mm_add_ps(prod4, _mm_movehl_ps(prod4, prod4));
|
|
276
|
+
prod4 = _mm_add_ss(prod4, _mm_shuffle_ps(prod4, prod4, 1));
|
|
277
|
+
result += _mm_cvtss_f32(prod4);
|
|
278
|
+
a += 4;
|
|
279
|
+
b += 4;
|
|
280
|
+
}
|
|
247
281
|
while (a < last) {
|
|
248
282
|
result = std::fma(*a++, *b++, result);
|
|
249
283
|
}
|
|
@@ -265,17 +299,20 @@ class InnerProductFloat_AVX2 {
|
|
|
265
299
|
}
|
|
266
300
|
|
|
267
301
|
if constexpr (HasDualSimd) {
|
|
268
|
-
const size_t
|
|
269
|
-
offset =
|
|
302
|
+
const size_t nc16 = dim / 16;
|
|
303
|
+
offset = nc16 * 16;
|
|
270
304
|
|
|
271
|
-
for (size_t c = 0; c <
|
|
272
|
-
size_t idx = c *
|
|
273
|
-
__m256
|
|
305
|
+
for (size_t c = 0; c < nc16; ++c) {
|
|
306
|
+
size_t idx = c * 16;
|
|
307
|
+
__m256 q_vec_lo = _mm256_loadu_ps(&query[idx]);
|
|
308
|
+
__m256 q_vec_hi = _mm256_loadu_ps(&query[idx + 8]);
|
|
274
309
|
|
|
275
310
|
for (size_t j = 0; j < BATCH_SIZE; ++j) {
|
|
276
311
|
const float* db_ = static_cast<const float*>(db[j]);
|
|
277
|
-
__m256
|
|
278
|
-
|
|
312
|
+
__m256 db_vec_lo = _mm256_loadu_ps(&db_[idx]);
|
|
313
|
+
__m256 db_vec_hi = _mm256_loadu_ps(&db_[idx + 8]);
|
|
314
|
+
s[j] = _mm256_fmadd_ps(q_vec_lo, db_vec_lo, s[j]);
|
|
315
|
+
s[j] = _mm256_fmadd_ps(q_vec_hi, db_vec_hi, s[j]);
|
|
279
316
|
}
|
|
280
317
|
}
|
|
281
318
|
}
|