deglib 0.1.0__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.1.0/CMakeLists.txt +24 -0
- deglib-0.1.0/LICENSE +21 -0
- deglib-0.1.0/MANIFEST.in +5 -0
- deglib-0.1.0/PKG-INFO +203 -0
- deglib-0.1.0/README.md +162 -0
- deglib-0.1.0/lib/CMakeLists.txt +126 -0
- deglib-0.1.0/lib/cmake_modules/DetectCPUFeatures.cmake +52 -0
- deglib-0.1.0/lib/deglib/CMakeLists.txt +10 -0
- deglib-0.1.0/lib/deglib/include/analysis.h +246 -0
- deglib-0.1.0/lib/deglib/include/builder.h +1441 -0
- deglib-0.1.0/lib/deglib/include/concurrent.h +68 -0
- deglib-0.1.0/lib/deglib/include/config.h +55 -0
- deglib-0.1.0/lib/deglib/include/deglib.h +12 -0
- deglib-0.1.0/lib/deglib/include/distances.h +744 -0
- deglib-0.1.0/lib/deglib/include/graph/readonly_graph.h +850 -0
- deglib-0.1.0/lib/deglib/include/graph/sizebounded_graph.h +1026 -0
- deglib-0.1.0/lib/deglib/include/graph.h +55 -0
- deglib-0.1.0/lib/deglib/include/memory.h +19 -0
- deglib-0.1.0/lib/deglib/include/repository.h +165 -0
- deglib-0.1.0/lib/deglib/include/search.h +149 -0
- deglib-0.1.0/lib/deglib/include/visited_list_pool.h +105 -0
- deglib-0.1.0/pyproject.toml +52 -0
- deglib-0.1.0/setup.cfg +4 -0
- deglib-0.1.0/setup.py +214 -0
- deglib-0.1.0/src/deg_cpp/deglib_cpp.cpp +392 -0
- deglib-0.1.0/src/deglib/__init__.py +19 -0
- deglib-0.1.0/src/deglib/analysis.py +85 -0
- deglib-0.1.0/src/deglib/benchmark.py +156 -0
- deglib-0.1.0/src/deglib/builder.py +237 -0
- deglib-0.1.0/src/deglib/distances.py +88 -0
- deglib-0.1.0/src/deglib/graph.py +640 -0
- deglib-0.1.0/src/deglib/repository.py +29 -0
- deglib-0.1.0/src/deglib/search.py +109 -0
- deglib-0.1.0/src/deglib/std.py +12 -0
- deglib-0.1.0/src/deglib/utils.py +56 -0
- deglib-0.1.0/src/deglib.egg-info/PKG-INFO +203 -0
- deglib-0.1.0/src/deglib.egg-info/SOURCES.txt +40 -0
- deglib-0.1.0/src/deglib.egg-info/dependency_links.txt +1 -0
- deglib-0.1.0/src/deglib.egg-info/requires.txt +5 -0
- deglib-0.1.0/src/deglib.egg-info/top_level.txt +2 -0
- deglib-0.1.0/tests/test_builder.py +127 -0
- deglib-0.1.0/tests/test_graph.py +262 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# python-bindings/CMakeLists.txt
|
|
2
|
+
cmake_minimum_required(VERSION 3.19)
|
|
3
|
+
project(deglib_cpp)
|
|
4
|
+
|
|
5
|
+
# Add python executable
|
|
6
|
+
if(DEFINED PYTHON_EXECUTABLE)
|
|
7
|
+
set(Python_EXECUTABLE ${PYTHON_EXECUTABLE})
|
|
8
|
+
endif()
|
|
9
|
+
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
|
|
10
|
+
|
|
11
|
+
# Add pybind11
|
|
12
|
+
find_package(pybind11 CONFIG REQUIRED)
|
|
13
|
+
|
|
14
|
+
# disable benchmark building
|
|
15
|
+
set(ENABLE_BENCHMARKS OFF CACHE BOOL "Disable benchmarks" FORCE)
|
|
16
|
+
|
|
17
|
+
# Add cpp-deglib
|
|
18
|
+
add_subdirectory(${CMAKE_SOURCE_DIR}/lib/)
|
|
19
|
+
pybind11_add_module(deglib_cpp src/deg_cpp/deglib_cpp.cpp)
|
|
20
|
+
|
|
21
|
+
# Specify the include directories
|
|
22
|
+
include_directories(${CMAKE_SOURCE_DIR}/lib/deglib/include)
|
|
23
|
+
|
|
24
|
+
target_link_libraries(deglib_cpp PRIVATE compile-options)
|
deglib-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Visual Computing Group
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
deglib-0.1.0/MANIFEST.in
ADDED
deglib-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: deglib
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python bindings for the Dynamic Exploration Graph library by Nico Hezel
|
|
5
|
+
Author: Nico Hezel
|
|
6
|
+
Author-email: Bruno Schilling <bruno.schilling@htw-berlin.de>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2024 Visual Computing Group
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Homepage, https://github.com/Visual-Computing/DynamicExplorationGraph
|
|
30
|
+
Keywords: anns-search,graph,python
|
|
31
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Requires-Python: >=3.11
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE
|
|
37
|
+
Requires-Dist: numpy>=1.21
|
|
38
|
+
Requires-Dist: psutil
|
|
39
|
+
Provides-Extra: test
|
|
40
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
41
|
+
|
|
42
|
+
# deglib: Python bindings for the Dynamic Exploration Graph
|
|
43
|
+
|
|
44
|
+
Python bindings for the C++ library Dynamic Exploration Graph used in the paper:
|
|
45
|
+
[Fast Approximate Nearest Neighbor Search with a Dynamic Exploration Graph using Continuous Refinement](https://arxiv.org/abs/2307.10479)
|
|
46
|
+
|
|
47
|
+
## Table of Contents
|
|
48
|
+
- [Installation](#installation)
|
|
49
|
+
- [Examples](#examples)
|
|
50
|
+
- [Naming](#naming)
|
|
51
|
+
- [Limitations](#limitations)
|
|
52
|
+
- [Troubleshooting](#troubleshooting)
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
### Using pip
|
|
57
|
+
```shell
|
|
58
|
+
pip install deglib
|
|
59
|
+
```
|
|
60
|
+
This will install a source package, that needs to compile the C++ code in order to create an optimized version for your system.
|
|
61
|
+
|
|
62
|
+
### Compiling from Source
|
|
63
|
+
|
|
64
|
+
**Create Virtual Environment**
|
|
65
|
+
```shell
|
|
66
|
+
# create virtualenv with virtualenvwrapper or venv
|
|
67
|
+
mkvirtualenv deglib
|
|
68
|
+
# or
|
|
69
|
+
python -m venv /path/to/deglib_env && . /path/to/deglib_env/bin/activate
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Get the Source**
|
|
73
|
+
```shell
|
|
74
|
+
# clone git repository
|
|
75
|
+
git clone git@github.com:Visual-Computing/DynamicExplorationGraph.git
|
|
76
|
+
cd DynamicExplorationGraph/python
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Install the Package from Source**
|
|
80
|
+
```shell
|
|
81
|
+
pip install setuptools pybind11 build
|
|
82
|
+
python setup.py copy_build_files # copy c++ library to ./lib/
|
|
83
|
+
pip install .
|
|
84
|
+
```
|
|
85
|
+
This will compile the C++ code and install deglib into your virtual environment, so it may take a while.
|
|
86
|
+
|
|
87
|
+
**Testing**
|
|
88
|
+
|
|
89
|
+
To execute all tests.
|
|
90
|
+
```shell
|
|
91
|
+
pytest
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Building Packages**
|
|
95
|
+
|
|
96
|
+
Build packages (sdist and wheels):
|
|
97
|
+
```shell
|
|
98
|
+
python -m build
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Note: If you want to publish linux wheels to pypi you have to convert
|
|
102
|
+
the wheel to musllinux-/manylinux-wheels.
|
|
103
|
+
This can be easily done using `cibuildwheel` (if docker is installed):
|
|
104
|
+
|
|
105
|
+
```shell
|
|
106
|
+
cibuildwheel --archs auto64 --output-dir dist
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Examples
|
|
110
|
+
### Loading Data
|
|
111
|
+
To load a dataset formatted like the [TexMex-Datasets](http://corpus-texmex.irisa.fr/):
|
|
112
|
+
```python
|
|
113
|
+
import deglib
|
|
114
|
+
import numpy as np
|
|
115
|
+
|
|
116
|
+
dataset: np.ndarray = deglib.repository.fvecs_read("path/to/data.fvecs")
|
|
117
|
+
num_samples, dims = dataset.shape
|
|
118
|
+
```
|
|
119
|
+
The dataset is a numpy array with shape (N, D), where N is the number of feature
|
|
120
|
+
vectors and D is the number of dimensions of each feature vector.
|
|
121
|
+
|
|
122
|
+
### Building a Graph
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
graph = deglib.builder.build_from_data(dataset, edges_per_vertex=32, callback="progress")
|
|
126
|
+
graph.save_graph("/path/to/graph.deg")
|
|
127
|
+
rd_graph = deglib.graph.load_readonly_graph("/path/to/graph.deg")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Searching the Graph
|
|
131
|
+
```python
|
|
132
|
+
# query can have shape (D,) or (Q, D), where
|
|
133
|
+
# D is the dimensionality of the dataset and
|
|
134
|
+
# Q is the number of queries.
|
|
135
|
+
query = np.random.random((dims,)).astype(np.float32)
|
|
136
|
+
result, dists = graph.search(query, eps=0.1, k=10) # get 10 nearest features to query
|
|
137
|
+
print('best dataset index:', result[0])
|
|
138
|
+
best_match = dataset[result[0]]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
For more examples see [tests](tests).
|
|
142
|
+
|
|
143
|
+
### Referencing C++ memory
|
|
144
|
+
Consider the following example:
|
|
145
|
+
```python
|
|
146
|
+
feature_vector = graph.get_feature_vector(42)
|
|
147
|
+
del graph
|
|
148
|
+
print(feature_vector)
|
|
149
|
+
```
|
|
150
|
+
This will crash as `feature_vector` is holding a reference to memory that is owned by `graph`. This can lead to undefined behaviour (most likely segmentation fault).
|
|
151
|
+
Be careful to keep objects in memory that are referenced. If you need it use the `copy=True` option:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
feature_vector = graph.get_feature_vector(10, copy=True)
|
|
155
|
+
del graph
|
|
156
|
+
print(feature_vector) # no problem
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Copying feature vectors will be slower.
|
|
160
|
+
|
|
161
|
+
## Naming
|
|
162
|
+
### Vertex = Feature Vector
|
|
163
|
+
Each vertex in the graph corresponds to a feature vector of the dataset.
|
|
164
|
+
|
|
165
|
+
### Internal Index vs External Label
|
|
166
|
+
There are two kinds of indices used in a graph: `internal_index` and `external_label`. Both are integers and specify
|
|
167
|
+
a vertex in a graph.
|
|
168
|
+
|
|
169
|
+
Internal Indices are dense, which means that every `internal_index < len(graph)` can be used.
|
|
170
|
+
For example: If you add 100 vertices and remove the vertex with internal_index 42, the last vertex in the graph will
|
|
171
|
+
be moved to index 42.
|
|
172
|
+
|
|
173
|
+
In contrast, external label is a user defined identifier for each added vertex
|
|
174
|
+
(see `builder.add_entry(external_label, feature_vector)`). Adding or Removing vertices to the graph will keep the
|
|
175
|
+
connection between external labels and associated feature vector.
|
|
176
|
+
|
|
177
|
+
When you create the external labels by starting with `0` and increasing it for each entry by `1` and don't remove
|
|
178
|
+
elements from the graph, external labels and internal indices are equal.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
# as long as no elements are removed
|
|
182
|
+
# external labels and internal indices are equal
|
|
183
|
+
for i, vec in enumerate(data):
|
|
184
|
+
builder.add_entry(i, vec)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Eps
|
|
188
|
+
The eps-search-parameter controls how many nodes are checked during search.
|
|
189
|
+
Lower eps values like 0.001 are faster but less accurate.
|
|
190
|
+
Higher eps values like 0.1 are slower but more accurate. Should always be greater 0.
|
|
191
|
+
|
|
192
|
+
### Relative Neighborhood Graph / RNG-conform
|
|
193
|
+
TODO
|
|
194
|
+
|
|
195
|
+
## Limitations
|
|
196
|
+
- The python wrapper at the moment only supports `float32` and `uint8` feature vectors.
|
|
197
|
+
|
|
198
|
+
## Troubleshooting
|
|
199
|
+
|
|
200
|
+
### BuildError: `pybind11/typing.h:104:58: error: ‘copy_n’ is not a member of ‘std’`
|
|
201
|
+
|
|
202
|
+
This is a pybind11 bug, that occurs when compiling it with gcc-14. Change the pybind version to 2.12.
|
|
203
|
+
|
deglib-0.1.0/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# deglib: Python bindings for the Dynamic Exploration Graph
|
|
2
|
+
|
|
3
|
+
Python bindings for the C++ library Dynamic Exploration Graph used in the paper:
|
|
4
|
+
[Fast Approximate Nearest Neighbor Search with a Dynamic Exploration Graph using Continuous Refinement](https://arxiv.org/abs/2307.10479)
|
|
5
|
+
|
|
6
|
+
## Table of Contents
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Examples](#examples)
|
|
9
|
+
- [Naming](#naming)
|
|
10
|
+
- [Limitations](#limitations)
|
|
11
|
+
- [Troubleshooting](#troubleshooting)
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### Using pip
|
|
16
|
+
```shell
|
|
17
|
+
pip install deglib
|
|
18
|
+
```
|
|
19
|
+
This will install a source package, that needs to compile the C++ code in order to create an optimized version for your system.
|
|
20
|
+
|
|
21
|
+
### Compiling from Source
|
|
22
|
+
|
|
23
|
+
**Create Virtual Environment**
|
|
24
|
+
```shell
|
|
25
|
+
# create virtualenv with virtualenvwrapper or venv
|
|
26
|
+
mkvirtualenv deglib
|
|
27
|
+
# or
|
|
28
|
+
python -m venv /path/to/deglib_env && . /path/to/deglib_env/bin/activate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Get the Source**
|
|
32
|
+
```shell
|
|
33
|
+
# clone git repository
|
|
34
|
+
git clone git@github.com:Visual-Computing/DynamicExplorationGraph.git
|
|
35
|
+
cd DynamicExplorationGraph/python
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Install the Package from Source**
|
|
39
|
+
```shell
|
|
40
|
+
pip install setuptools pybind11 build
|
|
41
|
+
python setup.py copy_build_files # copy c++ library to ./lib/
|
|
42
|
+
pip install .
|
|
43
|
+
```
|
|
44
|
+
This will compile the C++ code and install deglib into your virtual environment, so it may take a while.
|
|
45
|
+
|
|
46
|
+
**Testing**
|
|
47
|
+
|
|
48
|
+
To execute all tests.
|
|
49
|
+
```shell
|
|
50
|
+
pytest
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Building Packages**
|
|
54
|
+
|
|
55
|
+
Build packages (sdist and wheels):
|
|
56
|
+
```shell
|
|
57
|
+
python -m build
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Note: If you want to publish linux wheels to pypi you have to convert
|
|
61
|
+
the wheel to musllinux-/manylinux-wheels.
|
|
62
|
+
This can be easily done using `cibuildwheel` (if docker is installed):
|
|
63
|
+
|
|
64
|
+
```shell
|
|
65
|
+
cibuildwheel --archs auto64 --output-dir dist
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Examples
|
|
69
|
+
### Loading Data
|
|
70
|
+
To load a dataset formatted like the [TexMex-Datasets](http://corpus-texmex.irisa.fr/):
|
|
71
|
+
```python
|
|
72
|
+
import deglib
|
|
73
|
+
import numpy as np
|
|
74
|
+
|
|
75
|
+
dataset: np.ndarray = deglib.repository.fvecs_read("path/to/data.fvecs")
|
|
76
|
+
num_samples, dims = dataset.shape
|
|
77
|
+
```
|
|
78
|
+
The dataset is a numpy array with shape (N, D), where N is the number of feature
|
|
79
|
+
vectors and D is the number of dimensions of each feature vector.
|
|
80
|
+
|
|
81
|
+
### Building a Graph
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
graph = deglib.builder.build_from_data(dataset, edges_per_vertex=32, callback="progress")
|
|
85
|
+
graph.save_graph("/path/to/graph.deg")
|
|
86
|
+
rd_graph = deglib.graph.load_readonly_graph("/path/to/graph.deg")
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Searching the Graph
|
|
90
|
+
```python
|
|
91
|
+
# query can have shape (D,) or (Q, D), where
|
|
92
|
+
# D is the dimensionality of the dataset and
|
|
93
|
+
# Q is the number of queries.
|
|
94
|
+
query = np.random.random((dims,)).astype(np.float32)
|
|
95
|
+
result, dists = graph.search(query, eps=0.1, k=10) # get 10 nearest features to query
|
|
96
|
+
print('best dataset index:', result[0])
|
|
97
|
+
best_match = dataset[result[0]]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For more examples see [tests](tests).
|
|
101
|
+
|
|
102
|
+
### Referencing C++ memory
|
|
103
|
+
Consider the following example:
|
|
104
|
+
```python
|
|
105
|
+
feature_vector = graph.get_feature_vector(42)
|
|
106
|
+
del graph
|
|
107
|
+
print(feature_vector)
|
|
108
|
+
```
|
|
109
|
+
This will crash as `feature_vector` is holding a reference to memory that is owned by `graph`. This can lead to undefined behaviour (most likely segmentation fault).
|
|
110
|
+
Be careful to keep objects in memory that are referenced. If you need it use the `copy=True` option:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
feature_vector = graph.get_feature_vector(10, copy=True)
|
|
114
|
+
del graph
|
|
115
|
+
print(feature_vector) # no problem
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Copying feature vectors will be slower.
|
|
119
|
+
|
|
120
|
+
## Naming
|
|
121
|
+
### Vertex = Feature Vector
|
|
122
|
+
Each vertex in the graph corresponds to a feature vector of the dataset.
|
|
123
|
+
|
|
124
|
+
### Internal Index vs External Label
|
|
125
|
+
There are two kinds of indices used in a graph: `internal_index` and `external_label`. Both are integers and specify
|
|
126
|
+
a vertex in a graph.
|
|
127
|
+
|
|
128
|
+
Internal Indices are dense, which means that every `internal_index < len(graph)` can be used.
|
|
129
|
+
For example: If you add 100 vertices and remove the vertex with internal_index 42, the last vertex in the graph will
|
|
130
|
+
be moved to index 42.
|
|
131
|
+
|
|
132
|
+
In contrast, external label is a user defined identifier for each added vertex
|
|
133
|
+
(see `builder.add_entry(external_label, feature_vector)`). Adding or Removing vertices to the graph will keep the
|
|
134
|
+
connection between external labels and associated feature vector.
|
|
135
|
+
|
|
136
|
+
When you create the external labels by starting with `0` and increasing it for each entry by `1` and don't remove
|
|
137
|
+
elements from the graph, external labels and internal indices are equal.
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
# as long as no elements are removed
|
|
141
|
+
# external labels and internal indices are equal
|
|
142
|
+
for i, vec in enumerate(data):
|
|
143
|
+
builder.add_entry(i, vec)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Eps
|
|
147
|
+
The eps-search-parameter controls how many nodes are checked during search.
|
|
148
|
+
Lower eps values like 0.001 are faster but less accurate.
|
|
149
|
+
Higher eps values like 0.1 are slower but more accurate. Should always be greater 0.
|
|
150
|
+
|
|
151
|
+
### Relative Neighborhood Graph / RNG-conform
|
|
152
|
+
TODO
|
|
153
|
+
|
|
154
|
+
## Limitations
|
|
155
|
+
- The python wrapper at the moment only supports `float32` and `uint8` feature vectors.
|
|
156
|
+
|
|
157
|
+
## Troubleshooting
|
|
158
|
+
|
|
159
|
+
### BuildError: `pybind11/typing.h:104:58: error: ‘copy_n’ is not a member of ‘std’`
|
|
160
|
+
|
|
161
|
+
This is a pybind11 bug, that occurs when compiling it with gcc-14. Change the pybind version to 2.12.
|
|
162
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.19)
|
|
2
|
+
|
|
3
|
+
# Only interpret if() arguments as variables or keywords when unquoted. More
|
|
4
|
+
# details run "cmake --help-policy CMP0054"
|
|
5
|
+
cmake_policy(SET CMP0054 NEW)
|
|
6
|
+
|
|
7
|
+
project(
|
|
8
|
+
deg_lib
|
|
9
|
+
HOMEPAGE_URL "https://github.com/Neiko2002/DEG"
|
|
10
|
+
DESCRIPTION
|
|
11
|
+
"Dynamic Exploration Graphs for fast approximate nearest neighbor search and navigation in large image datasets"
|
|
12
|
+
VERSION 0.0.1
|
|
13
|
+
LANGUAGES CXX
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# build options
|
|
17
|
+
option(ENABLE_BENCHMARKS "compile benchmarks" ON)
|
|
18
|
+
option(FORCE_AVX2 "compile for avx2 support. Otherwise compile for this machine." OFF)
|
|
19
|
+
|
|
20
|
+
# https://cmake.org/cmake/help/latest/prop_tgt/CXX_STANDARD.html
|
|
21
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
22
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
23
|
+
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
24
|
+
|
|
25
|
+
add_library(compile-options INTERFACE)
|
|
26
|
+
target_compile_features(compile-options INTERFACE cxx_std_20)
|
|
27
|
+
target_compile_definitions(compile-options INTERFACE $<$<PLATFORM_ID:Windows>:NOMINMAX>)
|
|
28
|
+
|
|
29
|
+
# detecting CPU instruction support
|
|
30
|
+
# https://github.com/lemire/FastPFor/blob/master/CMakeLists.txt
|
|
31
|
+
if (APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
|
32
|
+
message(WARNING "You are compiling on an Apple M chip. At the moment deglib does not support ARM optimizations, so using deglib will be slow!")
|
|
33
|
+
endif()
|
|
34
|
+
|
|
35
|
+
if (FORCE_AVX2)
|
|
36
|
+
message(NOTICE "Compiling for avx2, ignoring native optimizations.")
|
|
37
|
+
|
|
38
|
+
# setup compiler flags
|
|
39
|
+
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
40
|
+
target_compile_options(
|
|
41
|
+
compile-options
|
|
42
|
+
INTERFACE -O3
|
|
43
|
+
-mavx2
|
|
44
|
+
-mfma
|
|
45
|
+
-fpic
|
|
46
|
+
-w
|
|
47
|
+
-fopenmp
|
|
48
|
+
-pthread
|
|
49
|
+
-ftree-vectorize
|
|
50
|
+
-ftree-vectorizer-verbose=0
|
|
51
|
+
)
|
|
52
|
+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
53
|
+
target_compile_options(
|
|
54
|
+
compile-options
|
|
55
|
+
INTERFACE -O2
|
|
56
|
+
-mavx2
|
|
57
|
+
-mfma
|
|
58
|
+
-fpic)
|
|
59
|
+
elseif(MSVC)
|
|
60
|
+
target_compile_options(
|
|
61
|
+
compile-options
|
|
62
|
+
INTERFACE /O2
|
|
63
|
+
/arch:AVX2
|
|
64
|
+
/W1
|
|
65
|
+
/openmp
|
|
66
|
+
/EHsc)
|
|
67
|
+
else()
|
|
68
|
+
message(WARNING "Unknown compiler for AVX2 Build: ${CMAKE_CXX_COMPILER_ID}")
|
|
69
|
+
endif()
|
|
70
|
+
|
|
71
|
+
else() # Native build
|
|
72
|
+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
|
|
73
|
+
include(DetectCPUFeatures)
|
|
74
|
+
|
|
75
|
+
# setup compiler flags
|
|
76
|
+
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
77
|
+
target_compile_options(
|
|
78
|
+
compile-options
|
|
79
|
+
INTERFACE -O3
|
|
80
|
+
-march=native
|
|
81
|
+
-mavx2
|
|
82
|
+
-mfma
|
|
83
|
+
-fpic
|
|
84
|
+
-w
|
|
85
|
+
-fopenmp
|
|
86
|
+
-pthread
|
|
87
|
+
-ftree-vectorize
|
|
88
|
+
-ftree-vectorizer-verbose=0)
|
|
89
|
+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
90
|
+
target_compile_options(
|
|
91
|
+
compile-options
|
|
92
|
+
INTERFACE -O2
|
|
93
|
+
-DNDEBUG
|
|
94
|
+
-march=native
|
|
95
|
+
-fpic)
|
|
96
|
+
elseif(MSVC)
|
|
97
|
+
# warning level 4 (show all)
|
|
98
|
+
target_compile_options(compile-options INTERFACE /W4)
|
|
99
|
+
|
|
100
|
+
# detecting SUPPORT_AVX2 or SSE2 support
|
|
101
|
+
cmake_host_system_information(RESULT SUPPORT_SSE2 QUERY HAS_SSE2)
|
|
102
|
+
if(SUPPORT_AVX2)
|
|
103
|
+
target_compile_options(compile-options INTERFACE /arch:AVX2)
|
|
104
|
+
elseif(SUPPORT_SSE2)
|
|
105
|
+
target_compile_options(compile-options INTERFACE /arch:SSE2)
|
|
106
|
+
else()
|
|
107
|
+
target_compile_options(compile-options INTERFACE /arch:native)
|
|
108
|
+
endif()
|
|
109
|
+
|
|
110
|
+
# disable string optimizations and function level linking
|
|
111
|
+
# https://stackoverflow.com/questions/5063334/what-is-the-difference-between-the-ox-and-o2-compiler-options
|
|
112
|
+
target_compile_options(compile-options INTERFACE $<$<CONFIG:Release>:/Ox>)
|
|
113
|
+
else()
|
|
114
|
+
message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER_ID}")
|
|
115
|
+
endif()
|
|
116
|
+
endif()
|
|
117
|
+
|
|
118
|
+
message("C++ compiler flags: ${CMAKE_CXX_FLAGS}")
|
|
119
|
+
message("C++ compiler flags release: ${CMAKE_CXX_FLAGS_RELEASE}")
|
|
120
|
+
|
|
121
|
+
add_subdirectory(deglib)
|
|
122
|
+
|
|
123
|
+
if (ENABLE_BENCHMARKS)
|
|
124
|
+
add_subdirectory(external/fmt)
|
|
125
|
+
add_subdirectory(benchmark)
|
|
126
|
+
endif()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
include(CheckCXXSourceCompiles)
|
|
2
|
+
|
|
3
|
+
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
|
|
4
|
+
|
|
5
|
+
set(SSE4PROG "
|
|
6
|
+
|
|
7
|
+
#include<smmintrin.h>
|
|
8
|
+
int main(){
|
|
9
|
+
__m128 x=_mm_set1_ps(0.5);
|
|
10
|
+
x=_mm_dp_ps(x,x,0x77);
|
|
11
|
+
return _mm_movemask_ps(x);
|
|
12
|
+
}")
|
|
13
|
+
|
|
14
|
+
set(AVXPROG "
|
|
15
|
+
|
|
16
|
+
#include<immintrin.h>
|
|
17
|
+
int main(){
|
|
18
|
+
__m128 x=_mm_set1_ps(0.5);
|
|
19
|
+
x=_mm_permute_ps(x,1);
|
|
20
|
+
return _mm_movemask_ps(x);
|
|
21
|
+
}")
|
|
22
|
+
|
|
23
|
+
set(AVX2PROG "
|
|
24
|
+
|
|
25
|
+
#include<immintrin.h>
|
|
26
|
+
int main(){
|
|
27
|
+
__m256i x=_mm256_set1_epi32(5);
|
|
28
|
+
x=_mm256_add_epi32(x,x);
|
|
29
|
+
return _mm256_movemask_epi8(x);
|
|
30
|
+
}")
|
|
31
|
+
|
|
32
|
+
if(MSVC)
|
|
33
|
+
set(CMAKE_REQUIRED_FLAGS "/EHsc /arch:SSE2")
|
|
34
|
+
check_cxx_source_compiles("${SSE4PROG}" SUPPORT_SSE42)
|
|
35
|
+
message(STATUS "SUPPORT_SSE42 ${SUPPORT_SSE42}")
|
|
36
|
+
set(CMAKE_REQUIRED_FLAGS "/EHsc /arch:AVX")
|
|
37
|
+
check_cxx_source_compiles("${AVXPROG}" SUPPORT_AVX)
|
|
38
|
+
message(STATUS "SUPPORT_AVX ${SUPPORT_AVX}")
|
|
39
|
+
set(CMAKE_REQUIRED_FLAGS "/EHsc /arch:AVX2")
|
|
40
|
+
check_cxx_source_compiles("${AVX2PROG}" SUPPORT_AVX2)
|
|
41
|
+
message(STATUS "SUPPORT_AVX2 ${SUPPORT_AVX2}")
|
|
42
|
+
else()
|
|
43
|
+
set(CMAKE_REQUIRED_FLAGS "-march=native -msse4.2")
|
|
44
|
+
check_cxx_source_compiles("${SSE4PROG}" SUPPORT_SSE42)
|
|
45
|
+
set(CMAKE_REQUIRED_FLAGS "-march=native -mavx")
|
|
46
|
+
check_cxx_source_compiles("${AVXPROG}" SUPPORT_AVX)
|
|
47
|
+
set(CMAKE_REQUIRED_FLAGS "-march=native -mavx2")
|
|
48
|
+
check_cxx_source_compiles("${AVX2PROG}" SUPPORT_AVX2)
|
|
49
|
+
endif()
|
|
50
|
+
|
|
51
|
+
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
|
|
52
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
cmake_minimum_required (VERSION 3.19)
|
|
2
|
+
|
|
3
|
+
project(deglib)
|
|
4
|
+
|
|
5
|
+
# setup the deg lib
|
|
6
|
+
# http://mariobadr.com/creating-a-header-only-library-with-cmake.html
|
|
7
|
+
add_library(DEG_LIB INTERFACE)
|
|
8
|
+
target_include_directories(DEG_LIB INTERFACE ${PROJECT_SOURCE_DIR}/include)
|
|
9
|
+
target_include_directories(DEG_LIB INTERFACE ${PROJECT_SOURCE_DIR}/include/graph)
|
|
10
|
+
target_compile_features(DEG_LIB INTERFACE cxx_std_20)
|