BlosSOM
Interactive dimensionality reduction on large datasets (EmbedSOM and FLOWER combined)
knn_edges.cpp
Go to the documentation of this file.
1/* This file is part of BlosSOM.
2 *
3 * Copyright (C) 2021 Mirek Kratochvil
4 * Sona Molnarova
5 *
6 * BlosSOM is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option)
9 * any later version.
10 *
11 * BlosSOM is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * BlosSOM. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "knn_edges.h"
21
22#include <cmath>
23#include <map>
24#include <set>
25
26constexpr float
27sqr(float x)
28{
29 return x * x;
30}
31
32void
33make_knn_edges(KnnEdgesData &data, LandmarkModel &landmarks, const size_t kns)
34{
35 /* TODO this might become pretty computation heavy. It might be better to
36 * be able to compute just several points in each frame to save framerate,
37 * and continuously rotate over the points. */
38
39 landmarks.edges.clear();
40 landmarks.edge_lengths.clear();
41
42 if (!(landmarks.n_landmarks() && kns)) {
43 return;
44 }
45
46 landmarks.edges.reserve((1 + kns) * landmarks.n_landmarks());
47 landmarks.edge_lengths.reserve(landmarks.edges.size());
48
49 std::map<std::pair<size_t, size_t>, float> nn;
50
51#if 1
52 std::vector<std::pair<float, size_t>> inn(kns + 1);
53 for (size_t i = 0; i < landmarks.n_landmarks(); ++i) {
54 size_t nns = 0;
55 for (size_t j = 0; j < landmarks.n_landmarks(); ++j) {
56 if (i == j)
57 continue;
58 float sqd = 0;
59 for (size_t di = 0; di < landmarks.d; ++di)
60 sqd += sqr(landmarks.hidim_vertices[di + landmarks.d * i] -
61 landmarks.hidim_vertices[di + landmarks.d * j]);
62
63 if (nns && inn[nns - 1].first <= sqd)
64 continue;
65 inn[nns] = { sqd, j };
66 for (size_t ni = nns; ni > 0; --ni) {
67 if (inn[ni].first < inn[ni - 1].first)
68 inn[ni].swap(inn[ni - 1]);
69 else
70 break;
71 }
72 if (nns < kns)
73 ++nns;
74 }
75
76 for (size_t ni = 0; ni < nns; ++ni)
77 nn[{ std::min(i, inn[ni].second), std::max(i, inn[ni].second) }] =
78 sqrt(inn[ni].second);
79 }
80#endif
81
82#if 1
83 // add a MST graph to keep connections
84 std::vector<bool> visited(landmarks.n_landmarks(), false);
85 std::set<std::tuple<float, size_t, size_t>> q;
86 q.insert({ 0, 0, 0 });
87 while (!q.empty()) {
88 auto [curdist, cur, from] = *q.begin();
89 q.erase(q.begin());
90
91 if (visited[cur])
92 continue;
93 visited[cur] = true;
94
95 if (cur != from)
96 nn[{ std::min(cur, from), std::max(cur, from) }] = sqrt(curdist);
97
98 for (size_t i = 0; i < landmarks.n_landmarks(); ++i) {
99 if (visited[i])
100 continue;
101 float sqd = 0;
102 for (size_t di = 0; di < landmarks.d; ++di)
103 sqd += sqr(landmarks.hidim_vertices[di + landmarks.d * cur] -
104 landmarks.hidim_vertices[di + landmarks.d * i]);
105
106 q.insert({ sqd, i, cur });
107 }
108 }
109#endif
110
111 for (auto &&p : nn) {
112 landmarks.edges.push_back(p.first);
113 landmarks.edge_lengths.push_back(0.05 * sqrt(p.second)); // TODO
114 }
115}
constexpr float sqr(float x)
Definition: knn_edges.cpp:27
void make_knn_edges(KnnEdgesData &data, LandmarkModel &landmarks, const size_t kns)
Definition: knn_edges.cpp:33
Model of the high- and low-dimensional landmarks.
size_t n_landmarks() const
Reurns number of the 2D landmarks.
std::vector< float > hidim_vertices
One-dimensional array storing d-dimensional landmark coordinates in row-major order.
std::vector< float > edge_lengths
Lengths of all edges.
size_t d
Dimension size.
std::vector< std::pair< size_t, size_t > > edges
Array of vertex ID pairs.