61 enum Scheme { RANKED, NUMBER, JACCARD };
149#if __has_include("igraph.h")
150 std::vector<igraph_integer_t>
edges;
159#if __has_include("igraph.h")
160 std::vector<igraph_real_t>
weights;
165#if __has_include("igraph.h")
173 igraph_vector_int_t edge_view;
174 igraph_vector_int_view(&edge_view,
edges.data(),
edges.size());
181 template<
class Indices_,
class Function_>
182 Results run(
const std::vector<Indices_>& indices, Function_ get_index)
const {
183 size_t ncells = indices.size();
186 std::vector<std::vector<std::pair<int, int> > > hosts(ncells);
187 for (
size_t i = 0; i < ncells; ++i) {
188 hosts[i].push_back(std::make_pair(0, i));
189 const auto& current = indices[i];
191 for (
auto x : current) {
192 hosts[get_index(x)].push_back(std::make_pair(counter, i));
198 std::vector<std::vector<int> > edge_stores(ncells);
199 std::vector<std::vector<double> > weight_stores(ncells);
201#ifndef SCRAN_CUSTOM_PARALLEL
202 #pragma omp parallel num_threads(nthreads)
205 SCRAN_CUSTOM_PARALLEL([&](
size_t,
size_t start,
size_t length) ->
void {
208 std::vector<int> current_score(ncells);
209 std::vector<int> current_added;
210 current_added.reserve(ncells);
212#ifndef SCRAN_CUSTOM_PARALLEL
214 for (
size_t j = 0; j < ncells; ++j) {
216 for (
size_t j = start, end = start + length; j < end; ++j) {
219 const auto& current_neighbors = indices[j];
220 int nneighbors = current_neighbors.size();
222 for (
int i = 0; i <= nneighbors; ++i) {
225 const int cur_neighbor = (i==0 ? j : get_index(current_neighbors[i-1]));
230 for (
const auto& h : hosts[cur_neighbor]) {
231 auto othernode = h.second;
234 int& existing_other = current_score[othernode];
235 if (weight_scheme == RANKED) {
237 int currank = h.first + i;
238 if (existing_other == 0) {
239 existing_other = currank;
240 current_added.push_back(othernode);
241 }
else if (existing_other > currank) {
242 existing_other = currank;
246 if (existing_other==0) {
247 current_added.push_back(othernode);
256 auto& current_edges = edge_stores[j];
257 current_edges.reserve(current_added.size() * 2);
258 auto& current_weights = weight_stores[j];
259 current_weights.reserve(current_added.size() * 2);
261 for (
auto othernode : current_added) {
262 int& otherscore = current_score[othernode];
264 if (weight_scheme == RANKED) {
265 finalscore =
static_cast<double>(nneighbors) - 0.5 *
static_cast<double>(otherscore);
267 finalscore = otherscore;
268 if (weight_scheme == JACCARD) {
269 finalscore = finalscore / (2 * (nneighbors + 1) - finalscore);
273 current_edges.push_back(j);
274 current_edges.push_back(othernode);
275 current_weights.push_back(std::max(finalscore, 1e-6));
280 current_added.clear();
282#ifndef SCRAN_CUSTOM_PARALLEL
287 }, ncells, nthreads);
292 for (
const auto& w : weight_stores) {
297 output.ncells = ncells;
299 output.weights.reserve(nedges);
300 for (
const auto& w : weight_stores) {
301 output.weights.insert(output.weights.end(), w.begin(), w.end());
303 weight_stores.clear();
304 weight_stores.shrink_to_fit();
306 output.edges.reserve(nedges * 2);
307 for (
const auto& e : edge_stores) {
308 output.edges.insert(output.edges.end(), e.begin(), e.end());
324 Results run(
size_t ndims,
size_t ncells,
const double* mat)
const {
325 std::unique_ptr<knncolle::Base<> > ptr;
327 ptr.reset(
new knncolle::VpTreeEuclidean<>(ndims, ncells, mat));
329 ptr.reset(
new knncolle::AnnoyEuclidean<>(ndims, ncells, mat));
331 return run(ptr.get());
341 template<
class Algorithm>
344 size_t ncells = search->nobs();
345 std::vector<std::vector<int> > indices(ncells);
347#ifndef SCRAN_CUSTOM_PARALLEL
348 #pragma omp parallel for num_threads(nthreads)
349 for (
size_t i = 0; i < ncells; ++i) {
351 SCRAN_CUSTOM_PARALLEL([&](
size_t,
size_t start,
size_t length) ->
void {
352 for (
size_t i = start, end = start + length; i < end; ++i) {
354 auto neighbors = search->find_nearest_neighbors(i, num_neighbors);
355 auto& current = indices[i];
356 for (
auto x : neighbors) {
357 current.push_back(x.first);
360#ifdef SCRAN_CUSTOM_PARALLEL
361 }, ncells, nthreads);
377 template<
typename Index_,
typename Distance_>
378 Results run(
const knncolle::NeighborList<Index_, Distance_>& neighbors)
const {
379 return run(neighbors, [](
const std::pair<Index_, Distance_>& x) -> Index_ {
return x.first; });
390 template<
class Indices_>
392 typedef typename std::remove_cv<typename std::remove_reference<decltype(std::declval<Indices_>()[0])>::type>::type Element;
393 return run(indices, [](Element i) -> Element {
return i; });