diff --git a/NEWS.md b/NEWS.md index af7699b8..bf8bb9da 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ # TreeDist 2.8.0.9000 (development) -- `SpectralEigens()` survives values of nEig larger than the input +- `SpectralEigens()` returns correct eigenvalues (smallest was overlooked) +- `SpectralEigens()` handles values of nEig larger than the input # TreeDist 2.8.0 (2024-07-25) diff --git a/R/spectral_clustering.R b/R/spectral_clustering.R index 5a2a800d..cb85e911 100644 --- a/R/spectral_clustering.R +++ b/R/spectral_clustering.R @@ -24,6 +24,9 @@ #' @family tree space functions #' @export SpectralEigens <- function(D, nn = 10L, nEig = 2L) { + if (nEig < 1) { + stop("nEig must be positive") + } MutualKnnGraph <- function(D, nn) { D <- as.matrix(D) @@ -32,13 +35,13 @@ SpectralEigens <- function(D, nn = 10L, nEig = 2L) { # intialize the knn matrix knn_mat <- matrix(FALSE, nrow = dims[[1]], ncol = dims[[2]]) - # find the 10 nearest neighbors for each point + # find the 10 nearest neighbours for each point for (i in seq_len(nrow(D))) { neighbor_index <- order(D[i, ])[2:(nn + 1)] knn_mat[i, ][neighbor_index] <- TRUE } - # Now we note that i,j are neighbors iff K[i,j] = 1 or K[j,i] = 1 + # Now we note that i,j are neighbours iff K[i,j] = 1 or K[j, i] = 1 knn_mat <- knn_mat | t(knn_mat) # find mutual knn # Return: @@ -64,7 +67,7 @@ SpectralEigens <- function(D, nn = 10L, nEig = 2L) { if (nL > nEig) { # Return the eigenvectors of the n_eig smallest eigenvalues: - ei[["vectors"]][, nL - rev(seq_len(nEig))] + ei[["vectors"]][, nL - (0:(nEig - 1))] } else { ei[["vectors"]] } diff --git a/tests/testthat/test-spectral_clustering.R b/tests/testthat/test-spectral_clustering.R new file mode 100644 index 00000000..5d3952bf --- /dev/null +++ b/tests/testthat/test-spectral_clustering.R @@ -0,0 +1,11 @@ +d <- dist(c(1:20, 60:41)) + +test_that("Spectral clustering fails gracefully", { + expect_error(SpectralEigens(d, nEig = 0), "nEig must be.*positive") +}) + +test_that("Spectral clustering works", { + allEig <- SpectralEigens(d, nEig = Inf) + expect_equal(dim(allEig), c(40, 40)) + expect_equal(SpectralEigens(d, nEig = 2), allEig[, 40:39]) +})