1# IGraph R package 2# Copyright (C) 2005-2012 Gabor Csardi <csardi.gabor@gmail.com> 3# 334 Harvard street, Cambridge, MA 02139 USA 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 2 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18# 02110-1301 USA 19# 20################################################################### 21 22################################################################### 23# Structure building 24################################################################### 25 26#' Add edges to a graph 27#' 28#' The new edges are given as a vertex sequence, e.g. internal 29#' numeric vertex ids, or vertex names. The first edge points from 30#' \code{edges[1]} to \code{edges[2]}, the second from \code{edges[3]} 31#' to \code{edges[4]}, etc. 32#' 33#' If attributes are supplied, and they are not present in the graph, 34#' their values for the original edges of the graph are set to \code{NA}. 35#' 36#' @param graph The input graph 37#' @param edges The edges to add, a vertex sequence with even number 38#' of vertices. 39#' @param ... Additional arguments, they must be named, 40#' and they will be added as edge attributes, for the newly added 41#' edges. See also details below. 42#' @param attr A named list, its elements will be added 43#' as edge attributes, for the newly added edges. See also details 44#' below. 45#' @return The graph, with the edges (and attributes) added. 46#' 47#' @export 48#' 49#' @aliases add.edges 50#' @family functions for manipulating graph structure 51#' 52#' @examples 53#' g <- make_empty_graph(n = 5) %>% 54#' add_edges(c(1,2, 2,3, 3,4, 4,5)) %>% 55#' set_edge_attr("color", value = "red") %>% 56#' add_edges(c(5,1), color = "green") 57#' E(g)[[]] 58#' plot(g) 59 60add_edges <- function(graph, edges, ..., attr = list()) { 61 if (!is_igraph(graph)) { 62 stop("Not a graph object") 63 } 64 65 attrs <- list(...) 66 attrs <- append(attrs, attr) 67 nam <- names(attrs) 68 if (length(attrs) != 0 && (is.null(nam) || any(nam==""))) { 69 stop("please supply names for attributes") 70 } 71 72 edges.orig <- ecount(graph) 73 on.exit( .Call(C_R_igraph_finalizer) ) 74 graph <- .Call(C_R_igraph_add_edges, graph, as.igraph.vs(graph, edges)-1) 75 edges.new <- ecount(graph) 76 77 if (edges.new-edges.orig != 0) { 78 idx <- seq(edges.orig+1, edges.new) 79 } else { 80 idx <- numeric() 81 } 82 83 eattrs <- .Call(C_R_igraph_mybracket2, graph, 9L, 4L) 84 for (i in seq(attrs)) { eattrs[[nam[i]]][idx] <- attrs[[nam[i]]] } 85 86 .Call(C_R_igraph_mybracket2_set, graph, 9L, 4L, eattrs) 87} 88 89#' Add vertices to a graph 90#' 91#' If attributes are supplied, and they are not present in the graph, 92#' their values for the original vertices of the graph are set to 93#' \code{NA}. 94#' 95#' @param graph The input graph. 96#' @param nv The number of vertices to add. 97#' @param ... Additional arguments, they must be named, 98#' and they will be added as vertex attributes, for the newly added 99#' vertices. See also details below. 100#' @param attr A named list, its elements will be added 101#' as vertex attributes, for the newly added vertices. See also details 102#' below. 103#' @return The graph, with the vertices (and attributes) added. 104#' 105#' @aliases add.vertices 106#' @family functions for manipulating graph structure 107#' 108#' @export 109#' @examples 110#' g <- make_empty_graph() %>% 111#' add_vertices(3, color = "red") %>% 112#' add_vertices(2, color = "green") %>% 113#' add_edges(c(1,2, 2,3, 3,4, 4,5)) 114#' g 115#' V(g)[[]] 116#' plot(g) 117 118add_vertices <- function(graph, nv, ..., attr=list()) { 119 if (!is_igraph(graph)) { 120 stop("Not a graph object") 121 } 122 123 attrs <- list(...) 124 attrs <- append(attrs, attr) 125 nam <- names(attrs) 126 if (length(attrs) != 0 && (is.null(nam) || any(nam==""))) { 127 stop("please supply names for attributes") 128 } 129 130 vertices.orig <- vcount(graph) 131 on.exit( .Call(C_R_igraph_finalizer) ) 132 graph <- .Call(C_R_igraph_add_vertices, graph, as.numeric(nv)) 133 vertices.new <- vcount(graph) 134 135 if (vertices.new-vertices.orig != 0) { 136 idx <- seq(vertices.orig+1, vertices.new) 137 } else { 138 idx <- numeric() 139 } 140 141 vattrs <- .Call(C_R_igraph_mybracket2, graph, 9L, 3L) 142 for (i in seq(attrs)) { vattrs[[nam[i]]][idx] <- attrs[[nam[i]]] } 143 144 .Call(C_R_igraph_mybracket2_set, graph, 9L, 3L, vattrs) 145} 146 147#' Delete edges from a graph 148#' 149#' @param graph The input graph. 150#' @param edges The edges to remove, specified as an edge sequence. 151#' @return The graph, with the edges removed. 152#' 153#' @aliases delete.edges 154#' @family functions for manipulating graph structure 155#' 156#' @export 157#' @examples 158#' g <- make_ring(10) %>% 159#' delete_edges(seq(1, 9, by = 2)) 160#' g 161#' 162#' g <- make_ring(10) %>% 163#' delete_edges("10|1") 164#' g 165 166delete_edges <- function(graph, edges) { 167 if (!is_igraph(graph)) { 168 stop("Not a graph object") 169 } 170 on.exit( .Call(C_R_igraph_finalizer) ) 171 .Call(C_R_igraph_delete_edges, graph, as.igraph.es(graph, edges)-1) 172} 173 174#' Delete vertices from a graph 175#' 176#' @param graph The input graph. 177#' @param v The vertices to remove, a vertex sequence. 178#' @return The graph, with the vertices removed. 179#' 180#' @aliases delete.vertices 181#' @family functions for manipulating graph structure 182#' 183#' @export 184#' @examples 185#' g <- make_ring(10) %>% 186#' set_vertex_attr("name", value = LETTERS[1:10]) 187#' g 188#' V(g) 189#' 190#' g2 <- delete_vertices(g, c(1,5)) %>% 191#' delete_vertices("B") 192#' g2 193#' V(g2) 194 195delete_vertices <- function(graph, v) { 196 if (!is_igraph(graph)) { 197 stop("Not a graph object") 198 } 199 on.exit( .Call(C_R_igraph_finalizer) ) 200 .Call(C_R_igraph_delete_vertices, graph, as.igraph.vs(graph, v)-1) 201} 202 203################################################################### 204# Structure query 205################################################################### 206 207#' The size of the graph (number of edges) 208#' 209#' \code{ecount} of an alias of this function. 210#' 211#' @param graph The graph. 212#' @return Numeric scalar, the number of edges. 213#' 214#' @aliases ecount 215#' @family structural queries 216#' 217#' @export 218#' @examples 219#' g <- sample_gnp(100, 2/100) 220#' gsize(g) 221#' 222#' # Number of edges in a G(n,p) graph 223#' replicate(100, sample_gnp(10, 1/2), simplify = FALSE) %>% 224#' vapply(gsize, 0) %>% 225#' hist() 226 227gsize <- function(graph) { 228 if (!is_igraph(graph)) { 229 stop("Not a graph object") 230 } 231 on.exit( .Call(C_R_igraph_finalizer) ) 232 .Call(C_R_igraph_ecount, graph) 233} 234 235#' Neighboring (adjacent) vertices in a graph 236#' 237#' A vertex is a neighbor of another one (in other words, the two 238#' vertices are adjacent), if they are incident to the same edge. 239#' 240#' @param graph The input graph. 241#' @param v The vertex of which the adjacent vertices are queried. 242#' @param mode Whether to query outgoing (\sQuote{out}), incoming 243#' (\sQuote{in}) edges, or both types (\sQuote{all}). This is 244#' ignored for undirected graphs. 245#' @return A vertex sequence containing the neighbors of the input vertex. 246#' 247#' @family structural queries 248#' 249#' @export 250#' @examples 251#' g <- make_graph("Zachary") 252#' n1 <- neighbors(g, 1) 253#' n34 <- neighbors(g, 34) 254#' intersection(n1, n34) 255 256neighbors <- function(graph, v, mode = c("out", "in", "all", "total")) { 257 if (!is_igraph(graph)) { 258 stop("Not a graph object") 259 } 260 if (is.character(mode)) { 261 mode <- igraph.match.arg(mode) 262 mode <- switch(mode, "out"=1, "in"=2, "all"=3, "total"=3) 263 } 264 on.exit( .Call(C_R_igraph_finalizer) ) 265 res <- .Call(C_R_igraph_neighbors, graph, as.igraph.vs(graph, v)-1, 266 as.numeric(mode)) 267 V(graph)[res + 1] 268} 269 270#' Incident edges of a vertex in a graph 271#' 272#' @param graph The input graph. 273#' @param v The vertex of which the incident edges are queried. 274#' @param mode Whether to query outgoing (\sQuote{out}), incoming 275#' (\sQuote{in}) edges, or both types (\sQuote{all}). This is 276#' ignored for undirected graphs. 277#' @return An edge sequence containing the incident edges of 278#' the input vertex. 279#' 280#' @family structural queries 281#' 282#' @export 283#' @examples 284#' g <- make_graph("Zachary") 285#' incident(g, 1) 286#' incident(g, 34) 287 288incident <- function(graph, v, mode=c("all", "out", "in", "total")) { 289 if (!is_igraph(graph)) { 290 stop("Not a graph object") 291 } 292 if (is_directed(graph)) { 293 mode <- igraph.match.arg(mode) 294 mode <- switch(mode, "out"=1, "in"=2, "all"=3, "total"=3) 295 } else { 296 mode=1 297 } 298 on.exit( .Call(C_R_igraph_finalizer) ) 299 res <- .Call(C_R_igraph_incident, graph, as.igraph.vs(graph, v)-1, 300 as.numeric(mode)) + 1L 301 302 if (igraph_opt("return.vs.es")) res <- create_es(graph, res) 303 304 res 305} 306 307#' Check whether a graph is directed 308#' 309#' @param graph The input graph 310#' @return Logical scalar, whether the graph is directed. 311#' 312#' @aliases is.directed 313#' @family structural queries 314#' 315#' @export 316#' @examples 317#' g <- make_ring(10) 318#' is_directed(g) 319#' 320#' g2 <- make_ring(10, directed = TRUE) 321#' is_directed(g2) 322 323is_directed <- function(graph) { 324 if (!is_igraph(graph)) { 325 stop("Not a graph object") 326 } 327 on.exit( .Call(C_R_igraph_finalizer) ) 328 .Call(C_R_igraph_is_directed, graph) 329} 330 331#' Incident vertices of some graph edges 332#' 333#' @param graph The input graph 334#' @param es The sequence of edges to query 335#' @param names Whether to return vertex names or 336#' numeric vertex ids. By default vertex names are used. 337#' @return A two column matrix of vertex names or vertex ids. 338#' 339#' @aliases get.edges get.edge 340#' @family structural queries 341#' 342#' @export 343#' @importFrom stats na.omit 344#' @examples 345#' g <- make_ring(5) 346#' ends(g, E(g)) 347 348ends <- function(graph, es, names = TRUE) { 349 350 if (!is_igraph(graph)) { 351 stop("Not a graph object") 352 } 353 354 es2 <- as.igraph.es(graph, na.omit(es)) - 1 355 res <- matrix(NA_integer_, ncol = length(es), nrow = 2) 356 357 on.exit( .Call(C_R_igraph_finalizer) ) 358 359 if (length(es) == 1) { 360 res[, !is.na(es)] <- .Call(C_R_igraph_get_edge, graph, es2) + 1 361 362 } else { 363 res[, !is.na(es)] <- .Call(C_R_igraph_edges, graph, es2) + 1 364 } 365 366 if (names && is_named(graph)) { 367 res <- vertex_attr(graph, "name")[res] 368 } 369 370 matrix(res, ncol = 2, byrow = TRUE) 371} 372 373#' @export 374 375get.edges <- function(graph, es) { 376 ends(graph, es, names = FALSE) 377} 378 379 380#' Find the edge ids based on the incident vertices of the edges 381#' 382#' Find the edges in an igraph graph that have the specified end points. This 383#' function handles multi-graph (graphs with multiple edges) and can consider 384#' or ignore the edge directions in directed graphs. 385#' 386#' igraph vertex ids are natural numbers, starting from one, up to the number 387#' of vertices in the graph. Similarly, edges are also numbered from one, up to 388#' the number of edges. 389#' 390#' This function allows finding the edges of the graph, via their incident 391#' vertices. 392#' 393#' @param graph The input graph. 394#' @param vp The incident vertices, given as vertex ids or symbolic vertex 395#' names. They are interpreted pairwise, i.e. the first and second are used for 396#' the first edge, the third and fourth for the second, etc. 397#' @param directed Logical scalar, whether to consider edge directions in 398#' directed graphs. This argument is ignored for undirected graphs. 399#' @param error Logical scalar, whether to report an error if an edge is not 400#' found in the graph. If \code{FALSE}, then no error is reported, and zero is 401#' returned for the non-existant edge(s). 402#' @param multi Logical scalar, whether to handle multiple edges properly. If 403#' \code{FALSE}, and a pair of vertices are given twice (or more), then always 404#' the same edge id is reported back for them. If \code{TRUE}, then the edge 405#' ids of multiple edges are correctly reported. 406#' @return A numeric vector of edge ids, one for each pair of input vertices. 407#' If there is no edge in the input graph for a given pair of vertices, then 408#' zero is reported. (If the \code{error} argument is \code{FALSE}.) 409#' @author Gabor Csardi \email{csardi.gabor@@gmail.com} 410#' @export 411#' @family structural queries 412#' 413#' @examples 414#' 415#' g <- make_ring(10) 416#' ei <- get.edge.ids(g, c(1,2, 4,5)) 417#' E(g)[ei] 418#' 419#' ## non-existant edge 420#' get.edge.ids(g, c(2,1, 1,4, 5,4)) 421#' 422get.edge.ids <- function(graph, vp, directed=TRUE, error=FALSE, multi=FALSE) { 423 if (!is_igraph(graph)) { 424 stop("Not a graph object") 425 } 426 on.exit( .Call(C_R_igraph_finalizer) ) 427 .Call(C_R_igraph_get_eids, graph, as.igraph.vs(graph, vp)-1, 428 as.logical(directed), as.logical(error), as.logical(multi)) + 1 429} 430 431 432#' Order (number of vertices) of a graph 433#' 434#' @param graph The graph 435#' @return Number of vertices, numeric scalar. 436#' 437#' @aliases vcount 438#' @family structural queries 439#' 440#' @export 441#' @examples 442#' g <- make_ring(10) 443#' gorder(g) 444 445gorder <- gorder 446 447#' Adjacent vertices of multiple vertices in a graph 448#' 449#' This function is similar to \code{\link{neighbors}}, but it queries 450#' the adjacent vertices for multiple vertices at once. 451#' 452#' @param graph Input graph. 453#' @param v The vertices to query. 454#' @param mode Whether to query outgoing (\sQuote{out}), incoming 455#' (\sQuote{in}) edges, or both types (\sQuote{all}). This is 456#' ignored for undirected graphs. 457#' @return A list of vertex sequences. 458#' 459#' @family structural queries 460#' @export 461#' @examples 462#' g <- make_graph("Zachary") 463#' adjacent_vertices(g, c(1, 34)) 464 465adjacent_vertices <- function(graph, v, 466 mode = c("out", "in", "all", "total")) { 467 468 if (!is_igraph(graph)) stop("Not a graph object") 469 470 vv <- as.igraph.vs(graph, v) - 1 471 mode <- switch(match.arg(mode), "out" = 1, "in" = 2, "all" = 3, "total" = 3) 472 473 on.exit(.Call(C_R_igraph_finalizer) ) 474 475 res <- .Call(C_R_igraph_adjacent_vertices, graph, vv, mode) 476 477 if (igraph_opt("return.vs.es")) { 478 res <- lapply(res, function(x) create_vs(graph, x + 1)) 479 } 480 481 if (is_named(graph)) names(res) <- V(graph)$name[vv + 1] 482 483 res 484} 485 486#' Incident edges of multiple vertices in a graph 487#' 488#' This function is similar to \code{\link{incident}}, but it 489#' queries multiple vertices at once. 490#' 491#' @param graph Input graph. 492#' @param v The vertices to query 493#' @param mode Whether to query outgoing (\sQuote{out}), incoming 494#' (\sQuote{in}) edges, or both types (\sQuote{all}). This is 495#' ignored for undirected graphs. 496#' @return A list of edge sequences. 497#' 498#' @family structural queries 499#' @export 500#' @examples 501#' g <- make_graph("Zachary") 502#' incident_edges(g, c(1, 34)) 503 504incident_edges <- function(graph, v, 505 mode = c("out", "in", "all", "total")) { 506 507 if (!is_igraph(graph)) stop("Not a graph object") 508 509 vv <- as.igraph.vs(graph, v) - 1 510 mode <- switch(match.arg(mode), "out" = 1, "in" = 2, "all" = 3, "total" = 3) 511 512 on.exit(.Call(C_R_igraph_finalizer) ) 513 514 res <- .Call(C_R_igraph_incident_edges, graph, vv, mode) 515 516 if (igraph_opt("return.vs.es")) { 517 res <- lapply(res, function(x) create_es(graph, x + 1)) 518 } 519 520 if (is_named(graph)) names(res) <- V(graph)$name[vv + 1] 521 522 res 523} 524