faissR provides native nearest-neighbour search, graph
construction, graph clustering, k-nearest-neighbour prediction, and
k-means utilities for R workflows that use large row-wise matrices. The
package is designed for high-throughput biological data analysis,
including single-cell, flow cytometry, imaging, and mass spectrometry
applications.
The package requires the FAISS C++ library for CPU indexes. CUDA, FAISS GPU indexes, NVIDIA cuVS, and RAPIDS libcugraph are optional. CPU-only installations do not need NVIDIA libraries, and explicit CUDA requests fail clearly when CUDA support is not available.
The main public functions are:
| Function | Purpose |
|---|---|
nn() |
nearest-neighbour search on host matrices |
nn_gpu() |
GPU-resident exact-family KNN result for downstream CUDA code |
candidate_knn() |
refine a supplied candidate neighbour set |
knn() and predict() |
supervised kNN fitting and prediction |
knn_graph() |
construct a weighted nearest-neighbour graph |
graph_cluster() |
random-walking, Louvain, or Leiden-style graph clustering |
fast_kmeans() |
CPU or optional CUDA k-means |
backend_info() and nn_capabilities() |
inspect compiled backends |
The examples use a small synthetic matrix with three groups. Rows are
observations and columns are features, matching the input convention
used by faissR.
library(faissR)
set.seed(100)
n_per_group <- 30L
p <- 8L
centers <- rbind(
rep(-2, p),
rep(0, p),
rep(2, p)
)
x <- do.call(rbind, lapply(seq_len(nrow(centers)), function(i) {
sweep(
matrix(rnorm(n_per_group * p, sd = 0.7), ncol = p),
2,
centers[i, ],
"+"
)
}))
groups <- factor(rep(LETTERS[1:3], each = n_per_group))
dim(x)
#> [1] 90 8
table(groups)
#> groups
#> A B C
#> 30 30 30backend_info() reports which compiled routes are
available in the current R session. On a CPU-only machine, CUDA-related
entries are expected to be unavailable.
backend_info()[, c("backend", "available", "knn_available")]
#> backend available knn_available
#> 1 cpu TRUE TRUE
#> 2 faiss TRUE TRUE
#> 3 faiss_gpu_cuvs FALSE FALSE
#> 4 cuvs FALSE FALSE
#> 5 cuda FALSE FALSE
#> 6 cugraph FALSE FALSEnn_capabilities() gives method, backend, and metric
support. The table can be large, so the example below shows only CPU
Euclidean rows.
caps <- nn_capabilities()
subset(
caps,
backend == "cpu" & metric == "euclidean",
select = c("method", "backend", "metric", "supported", "exact")
)
#> method backend metric supported exact
#> 5 auto cpu euclidean TRUE NA
#> 17 exact cpu euclidean TRUE TRUE
#> 29 flat cpu euclidean TRUE TRUE
#> 41 bruteforce cpu euclidean TRUE TRUE
#> 53 grid cpu euclidean TRUE TRUE
#> 65 hnsw cpu euclidean TRUE FALSE
#> 77 ivf cpu euclidean TRUE FALSE
#> 89 ivfpq cpu euclidean TRUE FALSE
#> 101 vamana cpu euclidean TRUE FALSE
#> 113 nsg cpu euclidean TRUE FALSE
#> 125 nndescent cpu euclidean TRUE FALSE
#> 137 ivfpq_fastscan cpu euclidean TRUE FALSE
#> 149 cagra cpu euclidean FALSE NAThe main entry point is nn(). Use
exclude_self = TRUE for self-KNN when each row is searched
against the same matrix and should not return itself.
nearest <- nn(
x,
k = 5,
backend = "cpu",
method = "exact",
metric = "euclidean",
exclude_self = TRUE,
n_threads = 2
)
nearest
#> faissR KNN
#> queries: 90
#> neighbors: 5
#> backend: faiss_flat_l2
#> metric: euclidean
#> first column: self-neighbor
dim(nearest$indices)
#> [1] 90 5
head(nearest$indices)
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 9 21 10 19 7
#> [2,] 12 30 14 21 8
#> [3,] 11 5 7 23 10
#> [4,] 7 11 14 8 18
#> [5,] 3 11 7 25 27
#> [6,] 12 30 19 27 21
head(round(nearest$distances, 3))
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1.151 1.493 1.731 1.757 1.760
#> [2,] 1.782 1.903 1.912 2.191 2.227
#> [3,] 0.789 1.035 1.114 1.286 1.398
#> [4,] 1.861 1.870 1.976 2.084 2.122
#> [5,] 1.035 1.172 1.709 1.773 2.005
#> [6,] 1.818 2.132 2.187 2.225 2.259The returned object stores both the public request and the implementation that actually ran.
c(
requested_backend = attr(nearest, "requested_backend"),
requested_method = attr(nearest, "requested_method"),
backend_used = attr(nearest, "backend_used"),
metric = attr(nearest, "metric"),
distance_type = attr(nearest, "distance_type")
)
#> requested_backend requested_method backend_used metric
#> "cpu" "exact" "faiss_flat_l2" "euclidean"
#> distance_type
#> "double"The default method = "auto" uses compiled shape-,
metric-, k-, backend-, and target-recall-aware rules. These
rules are deterministic; they do not run a slow tuning pass inside
ordinary user calls.
auto_nearest <- nn(
x,
k = 8,
backend = "cpu",
method = "auto",
metric = "euclidean",
exclude_self = TRUE,
n_threads = 2
)
c(
backend_used = attr(auto_nearest, "backend_used"),
requested_method = attr(auto_nearest, "requested_method")
)
#> backend_used requested_method
#> "cpu" "auto"For large two- or three-dimensional self-KNN,
method = "auto" can select the native grid route. The
explicit call below demonstrates that route on a small two-dimensional
matrix.
The public metric set is intentionally small:
euclidean;cosine;correlation;inner_product.Cosine normalizes each row before searching. Correlation first centers each row and then applies row normalization. Inner product ranks neighbours by larger raw dot product, while returned distances keep faissR’s smaller-is-better convention.
metric_results <- lapply(
c("euclidean", "cosine", "correlation", "inner_product"),
function(metric) {
out <- nn(
x,
k = 5,
backend = "cpu",
method = "exact",
metric = metric,
exclude_self = TRUE,
n_threads = 2
)
data.frame(
metric = metric,
backend_used = attr(out, "backend_used"),
first_distance = round(out$distances[1, 1], 4)
)
}
)
do.call(rbind, metric_results)
#> metric backend_used first_distance
#> 1 euclidean faiss_flat_l2 1.1514
#> 2 cosine faiss_flat_cosine 0.0173
#> 3 correlation faiss_flat_correlation 0.2154
#> 4 inner_product faiss_flat_ip 0.0000FAISS and cuVS consume float32 data internally. Ordinary R numeric
matrices are converted once for those compiled routes. If the optional
float package is installed, faissR can also
accept float::fl() input and return float32 distance
matrices with output = "float".
xf <- float::fl(x)
float_nearest <- nn(
xf,
k = 5,
backend = "cpu",
method = "exact",
metric = "euclidean",
exclude_self = TRUE,
output = "float",
n_threads = 2
)
c(
input_type = attr(float_nearest, "input_type"),
distance_type = attr(float_nearest, "distance_type")
)
#> input_type distance_type
#> "float32" "float32"
class(float_nearest$distances)
#> [1] "float32"
#> attr(,"package")
#> [1] "float"knn() can fit a model for repeated prediction, or it can
fit and predict in one call when Xtest is supplied. Fitted
FAISS Flat, HNSW, IVF, and IVFPQ indexes are reused by
predict() where supported.
fit <- knn(
Xtrain = x,
Ytrain = groups,
k = 7,
backend = "cpu",
method = "exact",
metric = "euclidean",
n_threads = 2
)
pred <- predict(fit, x[1:6, , drop = FALSE])
prob <- predict(fit, x[1:6, , drop = FALSE], type = "prob")
pred
#> [1] A A A A A A
#> attr(,"faissR_nn")
#> attr(,"faissR_nn")$k
#> [1] 7
#>
#> attr(,"faissR_nn")$requested_backend
#> [1] auto
#>
#> attr(,"faissR_nn")$requested_method
#> [1] exact
#>
#> attr(,"faissR_nn")$tuning
#> [1] auto
#>
#> attr(,"faissR_nn")$target_recall
#> [1] 0.99
#>
#> attr(,"faissR_nn")$cagra_implementation
#> [1] <NA>
#>
#> attr(,"faissR_nn")$cagra_build_algo
#> [1] <NA>
#>
#> attr(,"faissR_nn")$backend
#> [1] faiss_flat_l2
#>
#> attr(,"faissR_nn")$resolved_backend
#> [1] faiss_flat_l2
#>
#> attr(,"faissR_nn")$metric
#> [1] euclidean
#>
#> attr(,"faissR_nn")$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation
#> attr(,"faissR_nn")$approximation$strategy
#> [1] faiss_IndexFlatL2
#>
#> attr(,"faissR_nn")$approximation$backend
#> [1] faiss_flat_l2
#>
#> attr(,"faissR_nn")$approximation$library
#> [1] faiss
#>
#> attr(,"faissR_nn")$approximation$metric
#> [1] euclidean
#>
#> attr(,"faissR_nn")$approximation$input_type
#> [1] float32
#>
#> attr(,"faissR_nn")$approximation$fitted_index
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$index_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$index_type
#> [1] IndexFlatL2ExternalPtr
#>
#> attr(,"faissR_nn")$approximation$tuning_source
#> [1] none
#>
#> attr(,"faissR_nn")$approximation$tuning_source
#> [1] none
#>
#> attr(,"faissR_nn")$approximation$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$approximation$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$approximation$query_source
#> [1] fitted_index
#>
#>
#> attr(,"faissR_nn")$faiss
#> attr(,"faissR_nn")$faiss$index_type
#> [1] IndexFlatL2ExternalPtr
#>
#> attr(,"faissR_nn")$faiss$backend
#> [1] cpu
#>
#> attr(,"faissR_nn")$faiss$library
#> [1] faiss
#>
#> attr(,"faissR_nn")$faiss$metric
#> [1] euclidean
#>
#> attr(,"faissR_nn")$faiss$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_trained
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_training_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$build_train_call_count
#> [1] 0
#>
#> attr(,"faissR_nn")$faiss$search_train_call_count
#> [1] 0
#>
#> attr(,"faissR_nn")$faiss$vectors_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$faiss$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$faiss$query_source
#> [1] fitted_index
#>
#>
#> attr(,"faissR_nn")$cuvs
#> NULL
#>
#> attr(,"faissR_nn")$spatial_index
#> NULL
#>
#> attr(,"faissR_nn")$auto_selection
#> NULL
#>
#> attr(,"faissR_nn")$metric_transform
#> NULL
#>
#> attr(,"faissR_nn")$distance_transform
#> NULL
#>
#> attr(,"faissR_nn")$input_type
#> [1] float32
#>
#> attr(,"faissR_nn")$input_layout
#> [1] r_double_column_major_to_row_major_float32;fitted_index_query:r_double_column_major_to_row_major_float32
#>
#> attr(,"faissR_nn")$input_owns_data
#> [1] TRUE
#>
#> attr(,"faissR_nn")$float32_compatibility_conversion
#> [1] TRUE
#>
#> attr(,"faissR_nn")$distance_type
#> [1] double
#>
#> attr(,"faissR_nn")$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$query_source
#> [1] fitted_index
#>
#> Levels: A B C
round(prob, 3)
#> A B C
#> [1,] 1 0 0
#> [2,] 1 0 0
#> [3,] 1 0 0
#> [4,] 1 0 0
#> [5,] 1 0 0
#> [6,] 1 0 0
#> attr(,"faissR_nn")
#> attr(,"faissR_nn")$k
#> [1] 7
#>
#> attr(,"faissR_nn")$requested_backend
#> [1] "auto"
#>
#> attr(,"faissR_nn")$requested_method
#> [1] "exact"
#>
#> attr(,"faissR_nn")$tuning
#> [1] "auto"
#>
#> attr(,"faissR_nn")$target_recall
#> [1] 0.99
#>
#> attr(,"faissR_nn")$cagra_implementation
#> [1] NA
#>
#> attr(,"faissR_nn")$cagra_build_algo
#> [1] NA
#>
#> attr(,"faissR_nn")$backend
#> [1] "faiss_flat_l2"
#>
#> attr(,"faissR_nn")$resolved_backend
#> [1] "faiss_flat_l2"
#>
#> attr(,"faissR_nn")$metric
#> [1] "euclidean"
#>
#> attr(,"faissR_nn")$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation
#> attr(,"faissR_nn")$approximation$strategy
#> [1] "faiss_IndexFlatL2"
#>
#> attr(,"faissR_nn")$approximation$backend
#> [1] "faiss_flat_l2"
#>
#> attr(,"faissR_nn")$approximation$library
#> [1] "faiss"
#>
#> attr(,"faissR_nn")$approximation$metric
#> [1] "euclidean"
#>
#> attr(,"faissR_nn")$approximation$input_type
#> [1] "float32"
#>
#> attr(,"faissR_nn")$approximation$fitted_index
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$index_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$index_type
#> [1] "IndexFlatL2ExternalPtr"
#>
#> attr(,"faissR_nn")$approximation$tuning_source
#> [1] "none"
#>
#> attr(,"faissR_nn")$approximation$tuning_source
#> [1] "none"
#>
#> attr(,"faissR_nn")$approximation$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$approximation$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$approximation$query_source
#> [1] "fitted_index"
#>
#>
#> attr(,"faissR_nn")$faiss
#> attr(,"faissR_nn")$faiss$index_type
#> [1] "IndexFlatL2ExternalPtr"
#>
#> attr(,"faissR_nn")$faiss$backend
#> [1] "cpu"
#>
#> attr(,"faissR_nn")$faiss$library
#> [1] "faiss"
#>
#> attr(,"faissR_nn")$faiss$metric
#> [1] "euclidean"
#>
#> attr(,"faissR_nn")$faiss$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_trained
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_training_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$build_train_call_count
#> [1] 0
#>
#> attr(,"faissR_nn")$faiss$search_train_call_count
#> [1] 0
#>
#> attr(,"faissR_nn")$faiss$vectors_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$faiss$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$faiss$query_source
#> [1] "fitted_index"
#>
#>
#> attr(,"faissR_nn")$cuvs
#> NULL
#>
#> attr(,"faissR_nn")$spatial_index
#> NULL
#>
#> attr(,"faissR_nn")$auto_selection
#> NULL
#>
#> attr(,"faissR_nn")$metric_transform
#> NULL
#>
#> attr(,"faissR_nn")$distance_transform
#> NULL
#>
#> attr(,"faissR_nn")$input_type
#> [1] "float32"
#>
#> attr(,"faissR_nn")$input_layout
#> [1] "r_double_column_major_to_row_major_float32;fitted_index_query:r_double_column_major_to_row_major_float32"
#>
#> attr(,"faissR_nn")$input_owns_data
#> [1] TRUE
#>
#> attr(,"faissR_nn")$float32_compatibility_conversion
#> [1] TRUE
#>
#> attr(,"faissR_nn")$distance_type
#> [1] "double"
#>
#> attr(,"faissR_nn")$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$query_source
#> [1] "fitted_index"Immediate prediction uses the same interface:
immediate <- knn(
Xtrain = x,
Ytrain = groups,
Xtest = x[1:6, , drop = FALSE],
k = 7,
backend = "cpu",
method = "exact",
metric = "euclidean",
n_threads = 2
)
immediate
#> [1] A A A A A A
#> attr(,"faissR_nn")
#> attr(,"faissR_nn")$k
#> [1] 7
#>
#> attr(,"faissR_nn")$requested_backend
#> [1] cpu
#>
#> attr(,"faissR_nn")$requested_method
#> [1] exact
#>
#> attr(,"faissR_nn")$tuning
#> [1] auto
#>
#> attr(,"faissR_nn")$target_recall
#> [1] 0.99
#>
#> attr(,"faissR_nn")$cagra_implementation
#> [1] <NA>
#>
#> attr(,"faissR_nn")$cagra_build_algo
#> [1] <NA>
#>
#> attr(,"faissR_nn")$backend
#> [1] faiss_flat_l2
#>
#> attr(,"faissR_nn")$resolved_backend
#> [1] faiss_flat_l2
#>
#> attr(,"faissR_nn")$metric
#> [1] euclidean
#>
#> attr(,"faissR_nn")$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation
#> attr(,"faissR_nn")$approximation$strategy
#> [1] faiss_IndexFlatL2
#>
#> attr(,"faissR_nn")$approximation$backend
#> [1] faiss_flat_l2
#>
#> attr(,"faissR_nn")$approximation$library
#> [1] faiss
#>
#> attr(,"faissR_nn")$approximation$metric
#> [1] euclidean
#>
#> attr(,"faissR_nn")$approximation$input_type
#> [1] float32
#>
#> attr(,"faissR_nn")$approximation$fitted_index
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$index_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$index_type
#> [1] IndexFlatL2ExternalPtr
#>
#> attr(,"faissR_nn")$approximation$tuning_source
#> [1] none
#>
#> attr(,"faissR_nn")$approximation$tuning_source
#> [1] none
#>
#> attr(,"faissR_nn")$approximation$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$approximation$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$approximation$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$approximation$query_source
#> [1] fitted_index
#>
#>
#> attr(,"faissR_nn")$faiss
#> attr(,"faissR_nn")$faiss$index_type
#> [1] IndexFlatL2ExternalPtr
#>
#> attr(,"faissR_nn")$faiss$backend
#> [1] cpu
#>
#> attr(,"faissR_nn")$faiss$library
#> [1] faiss
#>
#> attr(,"faissR_nn")$faiss$metric
#> [1] euclidean
#>
#> attr(,"faissR_nn")$faiss$exact
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_trained
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$index_training_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$build_train_call_count
#> [1] 0
#>
#> attr(,"faissR_nn")$faiss$search_train_call_count
#> [1] 0
#>
#> attr(,"faissR_nn")$faiss$vectors_reused
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$faiss$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$faiss$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$faiss$query_source
#> [1] fitted_index
#>
#>
#> attr(,"faissR_nn")$cuvs
#> NULL
#>
#> attr(,"faissR_nn")$spatial_index
#> NULL
#>
#> attr(,"faissR_nn")$auto_selection
#> NULL
#>
#> attr(,"faissR_nn")$metric_transform
#> NULL
#>
#> attr(,"faissR_nn")$distance_transform
#> NULL
#>
#> attr(,"faissR_nn")$input_type
#> [1] float32
#>
#> attr(,"faissR_nn")$input_layout
#> [1] r_double_column_major_to_row_major_float32;fitted_index_query:r_double_column_major_to_row_major_float32
#>
#> attr(,"faissR_nn")$input_owns_data
#> [1] TRUE
#>
#> attr(,"faissR_nn")$float32_compatibility_conversion
#> [1] TRUE
#>
#> attr(,"faissR_nn")$distance_type
#> [1] double
#>
#> attr(,"faissR_nn")$batch_query
#> [1] TRUE
#>
#> attr(,"faissR_nn")$query_n
#> [1] 6
#>
#> attr(,"faissR_nn")$query_call_count
#> [1] 1
#>
#> attr(,"faissR_nn")$query_source
#> [1] fitted_index
#>
#> Levels: A B Cknn_graph() builds a weighted graph from a data matrix
or from a precomputed nn() result. Passing a precomputed
KNN object is useful when the same neighbours are reused by several
downstream methods.
g <- knn_graph(
x,
k = 8,
backend = "cpu",
method = "exact",
metric = "euclidean",
weight = "snn",
n_threads = 2
)
c(
n_vertices = g$n_vertices,
n_edges = g$n_edges,
weight_type = g$weight_type
)
#> n_vertices n_edges weight_type
#> "90" "1277" "snn"
head(g$from)
#> [1] 1 1 1 1 1 1
head(g$to)
#> [1] 2 3 4 5 6 7graph_cluster() accepts a graph, a KNN object, or a
matrix. CPU graph clustering is implemented in native C++ and does not
depend on igraph. Available clustering methods are
random_walking, louvain, and
leiden.
clusters <- graph_cluster(
g,
method = "louvain",
backend = "cpu",
n_threads = 2,
seed = 1
)
c(
method = clusters$method,
backend = clusters$backend,
n_communities = clusters$n_communities,
modularity = round(clusters$modularity, 3)
)
#> method backend n_communities modularity
#> "louvain" "cpu" "4" "0.631"
table(clusters$membership, groups)
#> groups
#> A B C
#> 1 30 0 0
#> 2 0 4 0
#> 3 0 26 0
#> 4 0 0 30For Louvain and Leiden, n_clusters is an optional
target-count convenience parameter. It is an alternative to direct
resolution control and is not a hard guarantee.
targeted <- graph_cluster(
g,
method = "louvain",
backend = "cpu",
n_clusters = 3,
n_threads = 2,
seed = 1
)
c(
requested = targeted$parameters$n_clusters_requested,
observed = targeted$n_communities,
selected_resolution = round(targeted$selected_resolution, 3)
)
#> requested observed selected_resolution
#> 3.00 3.00 0.02fast_kmeans() uses the same backend style as the
nearest-neighbour functions. The CPU route is available everywhere; CUDA
is optional.
km <- fast_kmeans(
x,
centers = 3,
backend = "cpu",
n_init = 2,
max_iter = 20
)
c(
backend = km$backend,
backend_library = km$backend_library,
converged = km$converged
)
#> backend backend_library converged
#> "faiss" "faiss" "FALSE"
table(km$cluster, groups)
#> groups
#> A B C
#> 1 0 0 30
#> 2 30 0 0
#> 3 0 30 0CUDA-specific calls should be guarded with
cuda_available() or inspected with
backend_info(). The example below is not evaluated on
CPU-only builders.
if (cuda_available()) {
gpu_knn <- nn_gpu(
x,
k = 15,
exclude_self = TRUE,
method = "auto",
metric = "euclidean",
tuning = "auto",
target_recall = 0.99
)
gpu_knn
host_copy <- gpu_knn_to_host(gpu_knn)
}nn_gpu() is for downstream CUDA consumers. It keeps
result buffers resident on the GPU and copies them back to R only when
gpu_knn_to_host() is called explicitly.
sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so; LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] faissR_0.99.15 BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] digest_0.6.39 R6_2.6.1 fastmap_1.2.0
#> [4] xfun_0.60 maketools_1.3.2 float_0.3-3
#> [7] cachem_1.1.0 parallel_4.6.1 knitr_1.51
#> [10] htmltools_0.5.9 rmarkdown_2.31 buildtools_1.0.0
#> [13] lifecycle_1.0.5 cli_3.6.6 sass_0.4.10
#> [16] jquerylib_0.1.4 compiler_4.6.1 sys_3.4.3
#> [19] tools_4.6.1 bslib_0.11.0 evaluate_1.0.5
#> [22] Rcpp_1.1.2 yaml_2.3.12 otel_0.2.0
#> [25] BiocManager_1.30.27 jsonlite_2.0.0 rlang_1.3.0