Skip to content

Commit

Permalink
update igraph use; interrupt depth-first search in n.comp.nb, add igr…
Browse files Browse the repository at this point in the history
…aph argument to n.comp.nb
  • Loading branch information
rsbivand committed Jun 12, 2024
1 parent 0e10019 commit 80262d0
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 27 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: spdep
Version: 1.3-5
Date: 2024-06-10
Version: 1.3-6
Date: 2024-06-12
Title: Spatial Dependence: Weighting Schemes, Statistics
Encoding: UTF-8
Authors@R: c(person("Roger", "Bivand", role = c("cre", "aut"),
Expand Down
6 changes: 5 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Version 1.3-5 (development)
# Version 1.3-6 (development)

* #160 handle `n.comp.nb` delay in `print.nb` and elsewhere when the total number of neighbours is large

# Version 1.3-5 (2025-06-10)

* #157 migrate ESRI Shapefile to GPKG files; convert bhicv.shp to GPKG

Expand Down
32 changes: 26 additions & 6 deletions R/components.R
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
# Copyright 2001 by Nicholas Lewin-Koh
# Copyright 2001 by Nicholas Lewin-Koh, igraph added RSB 2024
#


n.comp.nb <- function(nb.obj){
n.comp.nb <- function(nb.obj, igraph=FALSE){
if(!inherits(nb.obj,"nb"))stop("not a neighbours list")
nb.obj <- make.sym.nb(nb.obj)
comp <- rep(0,length(nb.obj))
comp <- .Call("g_components", nb.obj, as.integer(comp), PACKAGE="spdep")
answ <- list(nc=length(unique(comp)), comp.id=comp)
stopifnot(is.logical(igraph))
stopifnot(length(igraph) == 1L)
nb.sym <- is.symmetric.nb(nb.obj)
if (igraph) {
if (!requireNamespace("igraph", quietly=TRUE)) {
igraph <- !igraph
warning("igraph not available, set FALSE")
}
}
if (!igraph) {
if (!nb.sym) nb.obj <- make.sym.nb(nb.obj)
comp <- rep(0,length(nb.obj))
comp <- .Call("g_components", nb.obj, as.integer(comp), PACKAGE="spdep")
answ <- list(nc=length(unique(comp)), comp.id=comp)
} else {
stopifnot(requireNamespace("igraph", quietly=TRUE))
stopifnot(requireNamespace("spatialreg", quietly=TRUE))
B <- as(nb2listw(nb.obj, style="B", zero.policy=TRUE), "CsparseMatrix")

g1 <- igraph::graph_from_adjacency_matrix(B,
mode=ifelse(nb.sym, "undirected", "directed"))
c1 <- igraph::components(g1, mode="weak")
answ <- list(nc=c1$no, comp.id=c1$membership)
}
answ
}

32 changes: 15 additions & 17 deletions man/compon.Rd
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
% Copyright 2001 by Roger S. Bivand and Nicholas Lewin-Koh
% Copyright 2001-24 by Roger S. Bivand and Nicholas Lewin-Koh
\name{Graph Components}
\alias{n.comp.nb}
%\alias{reach.ij}
Expand All @@ -8,11 +8,13 @@
\code{n.comp.nb()} finds the number of disjoint connected subgraphs in the graph depicted by \code{nb.obj} - a spatial neighbours list object.
}
\usage{
n.comp.nb(nb.obj)
n.comp.nb(nb.obj, igraph=FALSE)
}
\arguments{
\item{nb.obj}{a neighbours list object of class \code{nb}}
\item{igraph}{default \code{FALSE}, if \code{TRUE} use \code{igraph::components} after converting the neighbour object to a sparse adjacency matrix then a graph}
}
\details{If \code{igraph=TRUE} and \code{attr(nb.obj, "sym")} is \code{FALSE}, the components of the directed graph will be found by a simple breadth-first search; if \code{igraph=FALSE} and \code{attr(nb.obj, "sym")} is \code{FALSE}, the object will be made symmetric (which may be time-consuming with large numbers of neighbours) and the components found by depth-first search. If \code{igraph=TRUE} or \code{FALSE} and \code{attr(nb.obj, "sym")} is \code{TRUE}, the components of the directed graph will be found by depth-first search.}
\value{
A list of:
\item{nc}{number of disjoint connected subgraphs}
Expand All @@ -32,11 +34,11 @@ table(res$comp.id)
plot(col2, coords, add=TRUE)
points(coords, col=res$comp.id, pch=16)
run <- FALSE
if (require(igraph, quietly=TRUE) && require(spatialreg, quietly=TRUE)) run <- TRUE
if (require("igraph", quietly=TRUE) && require("spatialreg", quietly=TRUE)) run <- TRUE
if (run) {
B <- as(nb2listw(col2, style="B", zero.policy=TRUE), "CsparseMatrix")
g1 <- graph.adjacency(B, mode="undirected")
c1 <- clusters(g1)
g1 <- graph_from_adjacency_matrix(B, mode="undirected")
c1 <- components(g1)
print(c1$no == res$nc)
}
if (run) {
Expand All @@ -46,21 +48,17 @@ if (run) {
print(all.equal(c1$csize, c(table(res$comp.id)), check.attributes=FALSE))
}
if (run) {
W <- as(nb2listw(col2, style="W", zero.policy=TRUE), "CsparseMatrix")
g1W <- graph.adjacency(W, mode="directed", weighted="W")
c1W <- clusters(g1W)
print(all.equal(c1W$membership, res$comp.id, check.attributes=FALSE))
resi <- n.comp.nb(col2, igraph=TRUE)
print(resi$nc == res$nc)
}
if (run) {
ow <- options("warn")$warn
options("warn"=2L)
# Matrix 1.4-2 vulnerability work-around
B1 <- try(get.adjacency(g1), silent=TRUE)
if (!inherits(B1, "try-error")) {
#B1 <- get.adjacency(g1)
print(all.equal(B, B1))
print(all.equal(resi$comp.id, res$comp.id))
}
options("warn"=ow)
if (run) {
W <- as(nb2listw(col2, style="W", zero.policy=TRUE), "CsparseMatrix")
g1W <- graph_from_adjacency_matrix(W, mode="directed", weighted="W")
c1W <- components(g1W)
print(all.equal(c1W$membership, res$comp.id, check.attributes=FALSE))
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/dfs_ncomp.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* Copyright 2001 by Nicholas Lewin-Koh. */
/* Copyright 2001 by Nicholas Lewin-Koh.
* interrupt added RSB 2024 */

#include "spdep.h"

Expand Down Expand Up @@ -33,6 +34,7 @@ SEXP g_components(SEXP nblst, SEXP cmpnm){
}

for(i=0; i < nvert; i++){
R_CheckUserInterrupt();
if(INTEGER(visited)[i]==WHITE){
INTEGER(visited)[i]=BLACK;
if(INTEGER(VECTOR_ELT(nblst,i))[0]==0){
Expand Down

0 comments on commit 80262d0

Please sign in to comment.