diff --git a/.Rbuildignore b/.Rbuildignore index 8ee7fcc..6ad8b96 100755 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -20,15 +20,12 @@ README[.]md ^README\_files$ [.]travis[.]yml ^appveyor\.yml$ - # Not-ready vignettes ^vignettes/simulating.+\.Rmd$ ^vignettes/structural.+\.Rmd$ - # CRAN ^NEWS\.md$ ^cran-comments\.md$ ^next_release\.md$ - ^src/rgraph_scale_free.+$ makefile diff --git a/ChangeLog b/ChangeLog index 66d493d..153f113 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-23 George G. Vega Yon + * : Working on making the package more light weight. + * : Checking included datasets duplicated columns. + * : Working on documentation + 2017-07-23 George G. Vega Yon * src/adjmat.cpp: rewriting egonet_attrs_cpp. Now more efficient should correct errors produced on windows. diff --git a/NAMESPACE b/NAMESPACE index 44e608e..764ffe9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -206,6 +206,7 @@ importFrom(igraph,graph_attr_names) importFrom(igraph,graph_from_adjacency_matrix) importFrom(igraph,is.loop) importFrom(igraph,layout_nicely) +importFrom(igraph,list.edge.attributes) importFrom(igraph,make_graph) importFrom(igraph,permute) importFrom(igraph,set_graph_attr) @@ -238,4 +239,4 @@ importFrom(utils,getFromNamespace) importFrom(utils,head) importFrom(utils,str) importMethodsFrom(Matrix,t) -useDynLib(netdiffuseR) +useDynLib(netdiffuseR, .registration = TRUE) diff --git a/NEWS.md b/NEWS.md index bfb6bc3..5a51f04 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,23 @@ +# Changes in netdiffuseR version 1.18.2999 (dev) + +## New functions + +## Bug fixes + +* `igraph_to_diffnet` was failing with the graph had no weights. + +* `drop_isolated` was not behaving well for diffnet objects. + + +## Other changes + +* Replacing some C++ functions by R functions in cases in which there + was no decrease in performance. + +* `plot_diffnet` function now has smaller margins, so looks more appealing. + + + # Changes in netdiffuseR version 1.18.1 (2017-07-22) ## New functions diff --git a/R/RcppExports.R b/R/RcppExports.R index 11b5b3b..0a5edad 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -1,76 +1,60 @@ # Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 -toa_mat_cpp <- function(year, t0, t1) { - .Call('_netdiffuseR_toa_mat_cpp', PACKAGE = 'netdiffuseR', year, t0, t1) -} - edgelist_to_adjmat_cpp <- function(edgelist, weights = as.numeric( c()), n = 0L, undirected = FALSE, self = FALSE, multiple = FALSE) { - .Call('_netdiffuseR_edgelist_to_adjmat_cpp', PACKAGE = 'netdiffuseR', edgelist, weights, n, undirected, self, multiple) + .Call(`_netdiffuseR_edgelist_to_adjmat_cpp`, edgelist, weights, n, undirected, self, multiple) } adjmat_to_edgelist_cpp <- function(adjmat, undirected = TRUE) { - .Call('_netdiffuseR_adjmat_to_edgelist_cpp', PACKAGE = 'netdiffuseR', adjmat, undirected) + .Call(`_netdiffuseR_adjmat_to_edgelist_cpp`, adjmat, undirected) } toa_diff_cpp <- function(year) { - .Call('_netdiffuseR_toa_diff_cpp', PACKAGE = 'netdiffuseR', year) -} - -isolated_cpp <- function(adjmat, undirected = TRUE) { - .Call('_netdiffuseR_isolated_cpp', PACKAGE = 'netdiffuseR', adjmat, undirected) -} - -drop_isolated_cpp <- function(adjmat, isolated, undirected = TRUE) { - .Call('_netdiffuseR_drop_isolated_cpp', PACKAGE = 'netdiffuseR', adjmat, isolated, undirected) + .Call(`_netdiffuseR_toa_diff_cpp`, year) } egonet_attrs_cpp <- function(graph, V, outer = TRUE, self = TRUE, valued = TRUE) { - .Call('_netdiffuseR_egonet_attrs_cpp', PACKAGE = 'netdiffuseR', graph, V, outer, self, valued) + .Call(`_netdiffuseR_egonet_attrs_cpp`, graph, V, outer, self, valued) } approx_geodesicCpp <- function(G, n = 6L, warn = FALSE) { - .Call('_netdiffuseR_approx_geodesicCpp', PACKAGE = 'netdiffuseR', G, n, warn) + .Call(`_netdiffuseR_approx_geodesicCpp`, G, n, warn) } infection_cpp <- function(graph, times, normalize = TRUE, K = 1L, r = 0.5, expdiscount = FALSE, n = 0L, valued = FALSE, outgoing = TRUE) { - .Call('_netdiffuseR_infection_cpp', PACKAGE = 'netdiffuseR', graph, times, normalize, K, r, expdiscount, n, valued, outgoing) + .Call(`_netdiffuseR_infection_cpp`, graph, times, normalize, K, r, expdiscount, n, valued, outgoing) } susceptibility_cpp <- function(graph, times, normalize = TRUE, K = 1L, r = 0.5, expdiscount = FALSE, n = 0L, valued = FALSE, outgoing = TRUE) { - .Call('_netdiffuseR_susceptibility_cpp', PACKAGE = 'netdiffuseR', graph, times, normalize, K, r, expdiscount, n, valued, outgoing) + .Call(`_netdiffuseR_susceptibility_cpp`, graph, times, normalize, K, r, expdiscount, n, valued, outgoing) } select_egoalter_cpp <- function(adjmat_t0, adjmat_t1, adopt_t0, adopt_t1) { - .Call('_netdiffuseR_select_egoalter_cpp', PACKAGE = 'netdiffuseR', adjmat_t0, adjmat_t1, adopt_t0, adopt_t1) -} - -sparse_indexes <- function(mat) { - .Call('_netdiffuseR_sparse_indexes', PACKAGE = 'netdiffuseR', mat) + .Call(`_netdiffuseR_select_egoalter_cpp`, adjmat_t0, adjmat_t1, adopt_t0, adopt_t1) } angle <- function(x0, y0, x1, y1) { - .Call('_netdiffuseR_angle', PACKAGE = 'netdiffuseR', x0, y0, x1, y1) + .Call(`_netdiffuseR_angle`, x0, y0, x1, y1) } sp_trimatl <- function(x) { - .Call('_netdiffuseR_sp_trimatl', PACKAGE = 'netdiffuseR', x) + .Call(`_netdiffuseR_sp_trimatl`, x) } sp_diag <- function(x, v) { - .Call('_netdiffuseR_sp_diag', PACKAGE = 'netdiffuseR', x, v) + .Call(`_netdiffuseR_sp_diag`, x, v) } unif_rand_w_exclusion <- function(n, e) { - .Call('_netdiffuseR_unif_rand_w_exclusion', PACKAGE = 'netdiffuseR', n, e) + .Call(`_netdiffuseR_unif_rand_w_exclusion`, n, e) } sp_as_undirected <- function(x) { - .Call('_netdiffuseR_sp_as_undirected', PACKAGE = 'netdiffuseR', x) + .Call(`_netdiffuseR_sp_as_undirected`, x) } bootnet_fillself <- function(graph, index, E) { - .Call('_netdiffuseR_bootnet_fillself', PACKAGE = 'netdiffuseR', graph, index, E) + .Call(`_netdiffuseR_bootnet_fillself`, graph, index, E) } #' Distribution over a grid @@ -103,7 +87,7 @@ bootnet_fillself <- function(graph, index, E) { #' grid_distribution(x,y,20) #' } grid_distribution <- function(x, y, nlevels = 100L) { - .Call('_netdiffuseR_grid_distribution', PACKAGE = 'netdiffuseR', x, y, nlevels) + .Call(`_netdiffuseR_grid_distribution`, x, y, nlevels) } #' Compute ego/alter edge coordinates considering alter's size and aspect ratio @@ -201,19 +185,19 @@ grid_distribution <- function(x, y, nlevels = 100L) { #' with(ecoords, arrows(x0,y0,x1,y1, length=.1)) #' @export edges_coords <- function(graph, toa, x, y, vertex_cex, undirected = TRUE, no_contemporary = TRUE, dev = as.numeric( c()), ran = as.numeric( c())) { - .Call('_netdiffuseR_edges_coords', PACKAGE = 'netdiffuseR', graph, toa, x, y, vertex_cex, undirected, no_contemporary, dev, ran) + .Call(`_netdiffuseR_edges_coords`, graph, toa, x, y, vertex_cex, undirected, no_contemporary, dev, ran) } edges_arrow <- function(x0, y0, x1, y1, height, width, beta = 1.5707963267949, dev = as.numeric( c()), ran = as.numeric( c())) { - .Call('_netdiffuseR_edges_arrow', PACKAGE = 'netdiffuseR', x0, y0, x1, y1, height, width, beta, dev, ran) + .Call(`_netdiffuseR_edges_arrow`, x0, y0, x1, y1, height, width, beta, dev, ran) } vertices_coords <- function(x, y, size, nsides, rot, dev = as.numeric( c()), ran = as.numeric( c())) { - .Call('_netdiffuseR_vertices_coords', PACKAGE = 'netdiffuseR', x, y, size, nsides, rot, dev, ran) + .Call(`_netdiffuseR_vertices_coords`, x, y, size, nsides, rot, dev, ran) } rgraph_er_cpp <- function(n = 10L, p = 0.3, undirected = TRUE, weighted = FALSE, self = FALSE) { - .Call('_netdiffuseR_rgraph_er_cpp', PACKAGE = 'netdiffuseR', n, p, undirected, weighted, self) + .Call(`_netdiffuseR_rgraph_er_cpp`, n, p, undirected, weighted, self) } #' Ring lattice graph @@ -232,49 +216,49 @@ rgraph_er_cpp <- function(n = 10L, p = 0.3, undirected = TRUE, weighted = FALSE, #' @export #' @family simulation functions ring_lattice <- function(n, k, undirected = FALSE) { - .Call('_netdiffuseR_ring_lattice', PACKAGE = 'netdiffuseR', n, k, undirected) + .Call(`_netdiffuseR_ring_lattice`, n, k, undirected) } rewire_endpoints <- function(graph, p, both_ends = FALSE, self = FALSE, multiple = FALSE, undirected = FALSE) { - .Call('_netdiffuseR_rewire_endpoints', PACKAGE = 'netdiffuseR', graph, p, both_ends, self, multiple, undirected) + .Call(`_netdiffuseR_rewire_endpoints`, graph, p, both_ends, self, multiple, undirected) } rewire_swap <- function(graph, nsteps = 100L, self = FALSE, multiple = FALSE, undirected = FALSE, pr_rewire = 0.5) { - .Call('_netdiffuseR_rewire_swap', PACKAGE = 'netdiffuseR', graph, nsteps, self, multiple, undirected, pr_rewire) + .Call(`_netdiffuseR_rewire_swap`, graph, nsteps, self, multiple, undirected, pr_rewire) } rewire_ws <- function(G, K, p = 0.0, self = FALSE, multiple = FALSE) { - .Call('_netdiffuseR_rewire_ws', PACKAGE = 'netdiffuseR', G, K, p, self, multiple) + .Call(`_netdiffuseR_rewire_ws`, G, K, p, self, multiple) } permute_graph_cpp <- function(x, self = FALSE, multiple = FALSE) { - .Call('_netdiffuseR_permute_graph_cpp', PACKAGE = 'netdiffuseR', x, self, multiple) + .Call(`_netdiffuseR_permute_graph_cpp`, x, self, multiple) } rgraph_ba_cpp <- function(graph, dgr, m = 1L, t = 10L, self = TRUE) { - .Call('_netdiffuseR_rgraph_ba_cpp', PACKAGE = 'netdiffuseR', graph, dgr, m, t, self) + .Call(`_netdiffuseR_rgraph_ba_cpp`, graph, dgr, m, t, self) } rgraph_ba_new_cpp <- function(m0 = 1L, m = 1L, t = 10L, self = TRUE) { - .Call('_netdiffuseR_rgraph_ba_new_cpp', PACKAGE = 'netdiffuseR', m0, m, t, self) + .Call(`_netdiffuseR_rgraph_ba_new_cpp`, m0, m, t, self) } rgraph_sf_homo <- function(eta, graph, dgr, m = 1L, t = 10L, self = TRUE) { - .Call('_netdiffuseR_rgraph_sf_homo', PACKAGE = 'netdiffuseR', eta, graph, dgr, m, t, self) + .Call(`_netdiffuseR_rgraph_sf_homo`, eta, graph, dgr, m, t, self) } rgraph_sf_homo_new <- function(eta, m0 = 1L, m = 1L, t = 10L, self = TRUE) { - .Call('_netdiffuseR_rgraph_sf_homo_new', PACKAGE = 'netdiffuseR', eta, m0, m, t, self) + .Call(`_netdiffuseR_rgraph_sf_homo_new`, eta, m0, m, t, self) } #' @export #' @rdname vertex_covariate_dist vertex_covariate_dist <- function(graph, X, p = 2.0) { - .Call('_netdiffuseR_vertex_covariate_dist', PACKAGE = 'netdiffuseR', graph, X, p) + .Call(`_netdiffuseR_vertex_covariate_dist`, graph, X, p) } vertex_mahalanobis_dist_cpp <- function(graph, X, S) { - .Call('_netdiffuseR_vertex_mahalanobis_dist_cpp', PACKAGE = 'netdiffuseR', graph, X, S) + .Call(`_netdiffuseR_vertex_mahalanobis_dist_cpp`, graph, X, S) } #' Comparisons at dyadic level @@ -309,27 +293,27 @@ vertex_mahalanobis_dist_cpp <- function(graph, X, S) { #' vertex_covariate_compare(G, x, "<=") #' @export vertex_covariate_compare <- function(graph, X, funname) { - .Call('_netdiffuseR_vertex_covariate_compare', PACKAGE = 'netdiffuseR', graph, X, funname) + .Call(`_netdiffuseR_vertex_covariate_compare`, graph, X, funname) } moran_cpp <- function(x, w) { - .Call('_netdiffuseR_moran_cpp', PACKAGE = 'netdiffuseR', x, w) + .Call(`_netdiffuseR_moran_cpp`, x, w) } struct_equiv_cpp <- function(graph, v = 1.0, unscaled = FALSE, inv = FALSE, invrep = 0.0) { - .Call('_netdiffuseR_struct_equiv_cpp', PACKAGE = 'netdiffuseR', graph, v, unscaled, inv, invrep) + .Call(`_netdiffuseR_struct_equiv_cpp`, graph, v, unscaled, inv, invrep) } matrix_compareCpp <- function(A, B, fun) { - .Call('_netdiffuseR_matrix_compareCpp', PACKAGE = 'netdiffuseR', A, B, fun) + .Call(`_netdiffuseR_matrix_compareCpp`, A, B, fun) } struct_test_mean <- function(y, funname, self = FALSE) { - .Call('_netdiffuseR_struct_test_mean', PACKAGE = 'netdiffuseR', y, funname, self) + .Call(`_netdiffuseR_struct_test_mean`, y, funname, self) } struct_test_var <- function(y, funname, self = FALSE) { - .Call('_netdiffuseR_struct_test_var', PACKAGE = 'netdiffuseR', y, funname, self) + .Call(`_netdiffuseR_struct_test_var`, y, funname, self) } #' Computes variance of \eqn{Y} at ego level @@ -363,6 +347,6 @@ struct_test_var <- function(y, funname, self = FALSE) { #' @seealso \code{\link{struct_test}} #' @family statistics ego_variance <- function(graph, Y, funname, all = FALSE) { - .Call('_netdiffuseR_ego_variance', PACKAGE = 'netdiffuseR', graph, Y, funname, all) + .Call(`_netdiffuseR_ego_variance`, graph, Y, funname, all) } diff --git a/R/adjmat.r b/R/adjmat.r index 9e057fb..91c7fd4 100644 --- a/R/adjmat.r +++ b/R/adjmat.r @@ -70,7 +70,7 @@ #' # Base data #' set.seed(123) #' n <- 5 -#' edgelist <- rgraph_er(n, as.edgelist=TRUE)[,c("ego","alter")] +#' edgelist <- rgraph_er(n, as.edgelist=TRUE, p=.2)[,c("ego","alter")] #' times <- sample.int(3, nrow(edgelist), replace=TRUE) #' w <- abs(rnorm(nrow(edgelist))) #' @@ -481,6 +481,16 @@ toa_mat <- function(obj, labels=NULL, t0=NULL, t1=NULL) { return(ans) } +toa_mat.default <- function(per, t0, t1) { + ans <- matrix(0L, ncol=t1-t0+1L, nrow=length(per)) + ans[cbind(1L:nrow(ans), per - t0 + 1L)] <- 1L + + list( + adopt = ans, + cumadopt = t(apply(ans, 1, cumsum)) + ) +} + # @rdname toa_mat # @export toa_mat.numeric <- function(times, labels=NULL, @@ -502,7 +512,7 @@ toa_mat.integer <- function(times, labels=NULL, t0 = min(times, na.rm = TRUE), t1 = max(times, na.rm=TRUE)) { # Rescaling - output <- toa_mat_cpp(times, t0, t1) + output <- toa_mat.default(times, t0, t1) # Naming cn <- t0:t1 @@ -601,6 +611,8 @@ toa_diff.integer <- function(times, t0, labels) { #' Find and remove unconnected vertices from the graph. #' @templateVar undirected TRUE #' @template graph_template +#' @templateVar undirected 1 +#' @templateVar self 1 #' @export #' @return #' When \code{graph} is an adjacency matrix: @@ -641,188 +653,79 @@ toa_diff.integer <- function(times, t0, labels) { #' @keywords manip #' @family data management functions #' @author George G. Vega Yon -isolated <- function(graph, undirected=getOption("diffnet.undirected")) { - switch (class(graph), - matrix = isolated.matrix(graph, undirected), - dgCMatrix = isolated.dgCMatrix(graph, undirected), - array = isolated.array(graph, undirected), - list = isolated.list(graph, undirected), - diffnet = isolated.list(graph$graph, graph$meta$undirected), +isolated <- function( + graph, + undirected = getOption("diffnet.undirected", FALSE), + self = getOption("diffnet.self", FALSE) +) { + ans <- switch (class(graph), + matrix = isolated.default(methods::as(graph, "dgCMatrix"), undirected, self), + dgCMatrix = isolated.default(graph, undirected, self), + array = lapply(apply(graph, 3, methods::as, Class="dgCMatrix"), isolated.default, + undirected=undirected, self=self), + list = lapply(graph, isolated.default, undirected=undirected, self=self), + diffnet = lapply(graph$graph, isolated.default, undirected=undirected, self=self), stopifnot_graph(graph) ) - # UseMethod("isolated") -} -# @export -# @rdname isolated -isolated.matrix <- function(graph, undirected=getOption("diffnet.undirected")) { - out <- isolated_cpp(methods::as(graph, "dgCMatrix"), undirected) - dimnames(out) <- list(rownames(graph), "isolated") - out + if (any(class(graph) %in% c("list", "diffnet", "array"))) + apply(do.call(cbind, ans), 1, all) + else ans + # UseMethod("isolated") } # @export # @rdname isolated -isolated.dgCMatrix <- function(graph, undirected=getOption("diffnet.undirected")) { - out <- isolated_cpp(graph, undirected) - dimnames(out) <- list(rownames(graph), "isolated") - out -} +isolated.default <- function( + graph, + undirected = getOption("diffnet.undirected", FALSE), + self = getOption("diffnet.self", FALSE) +) { -# @export -# @rdname isolated -isolated.array <- function(graph, undirected=getOption("diffnet.undirected")) { - nper <- as.integer(dim(graph)[3]) - n <- as.integer(dim(graph)[2]) + graph@x <- rep(1.0, length(graph@x)) + d <- Matrix::rowSums(graph) + if (undirected) + d <- d + Matrix::colSums(graph) - # Creating output list and anciliary vector (to see if is isolated or not!) - # iso <- Matrix::Matrix(0, ncol=nper, nrow=n, sparse=TRUE) - iso <- methods::new("dgCMatrix", Dim=c(n,nper), p=rep(0L,nper + 1L)) + if (!self) + d <- d - Matrix::diag(graph) - for(i in 1:nper) - iso[,i] <- isolated_cpp(methods::as(graph[,,i], "dgCMatrix"), undirected) + unname(d == 0) +} - # Names - rn <- rownames(graph) - if (!length(rn)) rn <- 1:n - tn <- dimnames(graph)[[3]] - if (!length(tn)) tn <- 1:nper +isolated.list <- function( + graph, + undirected = getOption("diffnet.undirected", FALSE), + self = getOption("diffnet.self", FALSE) + ) { - isolated <- structure( - ifelse(apply(iso, 1, sum)==nper, 1, 0), - dim=c(dim(graph)[1],1), dimnames = list(rn, "isolated")) + ids <- lapply(graph, isolated.default, undirected=undirected, self=self) - # Naming - dimnames(iso) <- list(rn, tn) + apply(do.call(cbind, ids), 1, all) - list( - isolated_t=iso, - isolated=isolated - ) } -# @export -# @rdname isolated -isolated.list <- function(graph, undirected=getOption("diffnet.undirected")) { - nper<- as.integer(length(graph)) - n <- as.integer(nrow(graph[[1]])) - - # Creating output list and anciliary vector (to see if is isolated or not!) - # iso <- Matrix::Matrix(0, ncol=nper, nrow=n, sparse=TRUE) - iso <- methods::new("dgCMatrix", Dim=c(n,nper), p=rep(0L,nper + 1L)) - - for(i in 1:nper) - iso[,i] <- isolated_cpp(graph[[i]], undirected) - isolated <- structure( - ifelse(apply(iso, 1, sum)==nper, 1, 0), - dim=c(n,1), dimnames=list(rownames(graph[[1]]), "isolated") - ) - - # Naming - dimnames(iso) <- list(rownames(graph[[1]]), names(graph)) - - list( - isolated_t=iso, - isolated=isolated - ) -} #' @export #' @rdname isolated -drop_isolated <- function(graph, undirected=getOption("diffnet.undirected")) { - out <- switch (class(graph), - matrix = drop_isolated.matrix(graph, undirected), - list = drop_isolated.list(graph, undirected), - diffnet = drop_isolated.list(graph$graph, graph$meta$undirected), - dgCMatrix = drop_isolated.dgCMatrix(graph, undirected), - array = drop_isolated.array(graph, undirected), - stopifnot_graph(graph) - ) - - if (inherits(graph, "diffnet")) { - graph$graph <- out - graph$meta$n <- nrow(out[[1]]) - graph$meta$ids <- row.names(out[[1]]) - - toa <- toa_mat(out, t0=graph$meta$pers[1], t1=graph$meta$pers[graph$meta$nper]) - graph$adopt <- toa$adopt - graph$cumadopt <- toa$cumadopt - - return(graph) - } - - return(out) -} - -# @rdname isolated -# @export -drop_isolated.matrix <- function(graph, undirected=getOption("diffnet.undirected")) { - iso <- isolated(graph, undirected) - out <- drop_isolated_cpp(methods::as(graph, "dgCMatrix"), iso, undirected) - - # Indexing the set of non-zero elements - iso <- rownames(iso[which(iso==0),,drop=FALSE]) - dimnames(out) <- list(iso, iso) - out -} - -# @rdname isolated -# @export -drop_isolated.dgCMatrix <- function(graph, undirected=getOption("diffnet.undirected")) { - iso <- isolated(graph, undirected) - out <- drop_isolated_cpp(graph, iso, undirected) - - # Indexing the set of non-zero elements - iso <- rownames(iso[which(iso==0),,drop=FALSE]) - dimnames(out) <- list(iso, iso) - out -} - -# @rdname isolated -# @export -drop_isolated.array <- function(graph, undirected=getOption("diffnet.undirected")) { - # Getting isolated vecs - iso <- isolated.array(graph, undirected)[[2]] - ison <- rownames(iso[which(iso==0),,drop=FALSE]) - - m <- sum(iso) - n <- dim(graph)[1] - t <- dim(graph)[3] - out <- vector("list", t) - - # Checking time names - tn <- dimnames(graph)[[3]] - if (!length(tn)) tn <- 1:t - names(out) <- tn - - # Removing - for(i in 1:t) { - out[[i]] <- drop_isolated_cpp(methods::as(graph[,,i], "dgCMatrix"), iso, undirected) - dimnames(out[[i]]) <- list(ison, ison) - } - - out -} - -# @rdname isolated -# @export -drop_isolated.list <- function(graph, undirected=getOption("diffnet.undirected")) { - # Getting isolated vecs - iso <- isolated.list(graph, undirected)[[2]] - ison <- rownames(iso[which(iso==0),,drop=FALSE]) - # m <- sum(iso) - # n <- nrow(graph[[1]]) - t <- length(graph) - out <- vector("list", t) - names(out) <- names(graph) - - # Removing - for(i in 1:t) { - out[[i]] <- drop_isolated_cpp(graph[[i]], iso, undirected) - dimnames(out[[i]]) <- list(ison,ison) - } +drop_isolated <- function( + graph, + undirected = getOption("diffnet.undirected", FALSE), + self = getOption("diffnet.self", FALSE) +) { + + # Find isolates + ids <- which(!isolated(graph)) + + if (inherits(graph, "list")) + lapply(graph, "[", i=ids, j=ids, drop=FALSE) + else if (inherits(graph, "diffnet")) + graph[ids,] + else if (inherits(graph, "dgCMatrix")) + graph[ids,,drop=FALSE][,ids,drop=FALSE] + else if (inherits(graph, "array")) + graph[ids,,,drop=FALSE][,ids,,drop=FALSE] - out } diff --git a/R/diffnet-class.R b/R/diffnet-class.R index 9d6a155..b3b7abc 100644 --- a/R/diffnet-class.R +++ b/R/diffnet-class.R @@ -747,8 +747,8 @@ diffnet.toa <- function(graph) { # checking stack nper <- ncol(mat[[1]]) - graph$adopt <- mat$adopt - graph$cumadopt <- mat$cumadopt + graph$adopt <- unname(mat$adopt) + graph$cumadopt <- unname(mat$cumadopt) graph diff --git a/R/diffnet-methods.r b/R/diffnet-methods.r index 746a30c..d647b04 100644 --- a/R/diffnet-methods.r +++ b/R/diffnet-methods.r @@ -512,6 +512,10 @@ plot_diffnet.list <- function(graph, cumadopt, slices, icol <- t(matrix(0:(mfrow.par[2]-1), nrow=mfrow.par[1], ncol=mfrow.par[2], byrow = TRUE)) # 2. Set up frame + oldpar <- par(no.readonly = TRUE) + on.exit(par(oldpar)) + par(mai = c(.1, .05, .05, .05), oma = rep(0,4)) + plot.new() ylim <- grDevices::extendrange(ylim, ylim) plot.window( @@ -571,17 +575,19 @@ plot_diffnet.list <- function(graph, cumadopt, slices, # Plotting - igraph::plot.igraph(ig, - vertex.color = cols, - layout = coords_adjs, - edge.color = edge.col, - vertex.size = rescale.fun(vertex.cex), - vertex.label=label, - add=TRUE, rescale=FALSE, - edge.arrow.size=edge.arrow.size, - vertex.frame.color = vertex.frame.color, - vertex.shape=shapes, - ...) + igraph::plot.igraph( + ig, + vertex.color = cols, + layout = coords_adjs, + edge.color = edge.col, + vertex.size = rescale.fun(vertex.cex), + vertex.label = label, + add = TRUE, + rescale = FALSE, + edge.arrow.size = edge.arrow.size, + vertex.frame.color = vertex.frame.color, + vertex.shape = shapes, + ...) } # Legend diff --git a/R/igraph.r b/R/igraph.r index 49fb643..fd022fb 100644 --- a/R/igraph.r +++ b/R/igraph.r @@ -140,8 +140,15 @@ igraph_to_diffnet <- function( if (!length(t0)) t0 <- min(toa, na.rm = TRUE) if (!length(t1)) t1 <- max(toa, na.rm = TRUE) - mat <- if (!islist) igraph::as_adj(graph, attr="weight") - else lapply(graph.list, igraph::as_adj, attr="weight") + mat <- if (!islist) { + wattr <- igraph::list.edge.attributes(graph) + wattr <- if ("weights" %in% wattr) "weights" else NULL + igraph::as_adj(graph, attr = wattr, sparse = TRUE) + } else lapply(graph.list, function(g) { + wattr <- igraph::list.edge.attributes(g) + wattr <- if ("weights" %in% wattr) "weights" else NULL + igraph::as_adj(g, attr=wattr, sparse=TRUE) + }) # Adjusting sizes if (!islist) diff --git a/R/imports.r b/R/imports.r index 39fc8c4..0b69998 100644 --- a/R/imports.r +++ b/R/imports.r @@ -4,13 +4,13 @@ NULL #' @importFrom sna gplot as.sociomatrix.sna #' @importFrom igraph graph_from_adjacency_matrix set_vertex_attr #' any_multiple graph_attr_names as_adj is.loop set_graph_attr V permute make_graph -#' layout_nicely graph_attr +#' layout_nicely graph_attr list.edge.attributes #' @importFrom network as.edgelist is.multiplex is.directed has.loops as.network #' get.network.attribute list.vertex.attributes #' @importFrom networkDynamic networkDynamic network.extract network.collapse NULL -#' @useDynLib netdiffuseR +#' @useDynLib netdiffuseR, .registration = TRUE NULL # Importing from the Matrix pkg ------------------------------------------------ diff --git a/R/plot_diffnet2.R b/R/plot_diffnet2.R index 8efe366..03f6ee3 100644 --- a/R/plot_diffnet2.R +++ b/R/plot_diffnet2.R @@ -298,6 +298,7 @@ plot_diffnet2.default <- function( #' #' # Example with a random graph -------------------------------------------------- #' +#' \dontrun{ #' set.seed(1231) #' #' # Random scale-free diffusion network @@ -324,6 +325,7 @@ plot_diffnet2.default <- function( #' mtext("Both networks have the same distribution on times of adoption", 1, #' outer = TRUE) #' par(oldpar) +#' } #' #' # Example with Brazilian Farmers -------------------------------------------- #' \dontrun{ diff --git a/R/random_graph.R b/R/random_graph.R index 2302d56..808a09c 100644 --- a/R/random_graph.R +++ b/R/random_graph.R @@ -52,7 +52,7 @@ #' @family simulation functions #' @include graph_data.r #' @author George G. Vega Yon -rgraph_er <- function(n=10, t=1, p=0.3, undirected=getOption("diffnet.undirected"), weighted=FALSE, +rgraph_er <- function(n=10, t=1, p=0.01, undirected=getOption("diffnet.undirected"), weighted=FALSE, self=getOption("diffnet.self"), as.edgelist=FALSE) { # Generating the random graph diff --git a/R/rdiffnet.R b/R/rdiffnet.R index cb8669d..b62a21c 100644 --- a/R/rdiffnet.R +++ b/R/rdiffnet.R @@ -73,6 +73,22 @@ #' If \code{seed.graph} is provided, no random graph is generated and the simulation #' is applied using that graph instead. #' +#' \code{rewire.args} has the following default options: +#' +#' \tabular{ll}{ +#' \code{p} \tab \code{.1} \cr +#' \code{undirected} \tab \code{getOption("diffnet.undirected", FALSE)} \cr +#' \code{self} \tab \code{getOption("diffnet.self", FALSE)} +#' } +#' +#' \code{exposure.args} has the following default options: +#' +#' \tabular{ll}{ +#' \code{outgoing} \tab \code{TRUE} \cr +#' \code{valued} \tab \code{getOption("diffnet.valued", FALSE)} \cr +#' \code{normalized} \tab \code{TRUE} +#' } +#' #' @examples #' # Asimple example ----------------------------------------------------------- #' set.seed(123) @@ -88,30 +104,32 @@ #' newMI <- rdiffnet(seed.graph = medInnovationsDiffNet$graph, #' threshold.dist = threshold(medInnovationsDiffNet), rewire=FALSE) #' +#' #' @author George G. Vega Yon rdiffnet <- function( n, t, - seed.nodes="random", - seed.p.adopt=0.05, - seed.graph="scale-free", - rgraph.args=list(), - rewire=TRUE, - rewire.args=list( - p=.1, - undirected= getOption("diffnet.undirected", FALSE), - self = getOption("diffnet.self", FALSE) - ), - threshold.dist=function(x) runif(1), - exposure.args=list( - outgoing=TRUE, - valued=getOption("diffnet.valued", FALSE), - normalized=TRUE - ), - name="A diffusion network", - behavior="Random contagion" + seed.nodes = "random", + seed.p.adopt = 0.05, + seed.graph = "scale-free", + rgraph.args = list(), + rewire = TRUE, + rewire.args = list(), + threshold.dist = function(x) runif(1), + exposure.args = list(), + name = "A diffusion network", + behavior = "Random contagion" ) { + # Checking options + if (!length(rewire.args[["p"]])) rewire.args[["p"]] <- .1 + if (!length(rewire.args[["undirected"]])) rewire.args[["undirected"]] <- getOption("diffnet.undirected", FALSE) + if (!length(rewire.args[["self"]])) rewire.args[["self"]] <- getOption("diffnet.self", FALSE) + + if (!length(exposure.args[["outgoing"]])) exposure.args[["outgoing"]] <- TRUE + if (!length(exposure.args[["valued"]])) exposure.args[["valued"]] <- getOption("diffnet.valued", FALSE) + if (!length(exposure.args[["normalized"]])) exposure.args[["normalized"]] <- TRUE + # Step 0.0: Creating the network seed ---------------------------------------- # Checking the class of the seed.graph test <- class(seed.graph) @@ -137,15 +155,23 @@ rdiffnet <- function( # In the case of calling a function } else if ("character" %in% test) { + + # Scale-free networks ------------------------------------------------------ if (seed.graph == "scale-free") { + if (!length(rgraph.args$m0)) rgraph.args$t <- n-1L sgraph <- do.call(rgraph_ba, rgraph.args) + + # Bernoulli graphs --------------------------------------------------------- } else if (seed.graph == "bernoulli") { + rgraph.args$n <- n sgraph <- do.call(rgraph_er, rgraph.args) + + # Small-world network ------------------------------------------------------ } else if (seed.graph == "small-world") { rgraph.args$n <- n @@ -153,6 +179,7 @@ rdiffnet <- function( if (!length(rgraph.args$p)) rgraph.args$p <- .1 sgraph <- do.call(rgraph_ws, rgraph.args) + } else stop("Invalid -seed.graph-. It should be either ", "'scale-free\', \'bernoulli\' or \'small-world\'.") @@ -161,19 +188,24 @@ rdiffnet <- function( graph <- rep(list(sgraph), t) } else if (test %in% c("matrix", "dgCMatrix", "array")) { + # If not dgCMatrix - if ("array" %in% test) { + if ("array" %in% test) sgraph <- apply(seed.graph, 3, function(x) methods::as(x, "dgCMatrix")) - } else { + else sgraph <- methods::as(seed.graph, "dgCMatrix") - } + } else if ("list" %in% test) { + sgraph <- seed.graph + } else if ("diffnet" %in% test) { + sgraph <- seed.graph$graph - }else { + + } else stop("Invalid argument for -seed.graph-. No support for objects of class -",test,"-.") - } + # Checking baseline graph -------------------------------------------------- meta <- classify_graph(sgraph) @@ -196,23 +228,31 @@ rdiffnet <- function( # If static, t must be provided, otherwise t should be missing if (meta$nper == 1) { - if (missing(t)) { + + if (missing(t)) stop("When -seed.graph- is static, -t- must be provided.") - } else { + else sgraph <- rep(list(sgraph), t) - } + } else { - if (!missing(t)) warning("When -seed.graph- is dynamic, -t- shouldn't be provided.") + + if (!missing(t)) + warning("When -seed.graph- is dynamic, -t- shouldn't be provided.") + t <- meta$nper + } # Step 0.1: Rewiring or not ------------------------------------------------ # Rewiring - if (rewire) sgraph <- do.call(rewire_graph, c(list(graph=sgraph), rewire.args)) + if (rewire) + sgraph <- do.call(rewire_graph, c(list(graph=sgraph), rewire.args)) # Number of initial adopters - if (n*seed.p.adopt < 1) warning("Set of initial adopters set to 1.") + if (n*seed.p.adopt < 1) + warning("Set of initial adopters set to 1.") + n0 <- max(1, n*seed.p.adopt) # Step 0.1: Setting the seed nodes ------------------------------------------- @@ -220,22 +260,32 @@ rdiffnet <- function( toa <- matrix(NA, ncol=1, nrow= n) if (length(seed.nodes) == 1) { + if (seed.nodes %in% c("central","marginal")) { + + # Creating a degree ranking d <- dgr(sgraph)[,1,drop=FALSE] decre <- ifelse(seed.nodes == "central", TRUE, FALSE) d <- rownames(d[order(d, decreasing = decre),,drop=FALSE]) d <- d[1:floor(n0)] d <- as.numeric(d) + } else if (seed.nodes == "random") { + d <- sample.int(n, floor(n0)) + } else stop("Unsupported -seed.nodes- value. It must be either \"central\", \"marginal\", or \"random\"") + } else if (!inherits(seed.nodes, "character")) { + d <- seed.nodes - } else stop("Unsupported -seed.nodes- value. See the manual for references.") + + } else + stop("Unsupported -seed.nodes- value. See the manual for references.") # Setting seed nodes via vector - toa[d] <- 1L + toa[d] <- 1L cumadopt[d,] <- 1L # Step 3.0: Thresholds ------------------------------------------------------- @@ -250,14 +300,18 @@ rdiffnet <- function( stop("Incorrect length for -threshold.dist- (",length(threshold.dist),")", ". It should be a vector of length ",n,".") } else if (is.vector(threshold.dist)) { + thr <- threshold.dist # Must match the length of n if (length(thr) != n) stop("Incorrect length for -threshold.dist- (",length(threshold.dist),")", ". It should be a vector of length ",n,".") + } else { + stop("-threshold.dist- must be either a vector of length -n- or a function.") + } } diff --git a/data-raw/brfarmers.R b/data-raw/brfarmers.R index fb4f32c..e8f5d8f 100644 --- a/data-raw/brfarmers.R +++ b/data-raw/brfarmers.R @@ -1,7 +1,11 @@ rm(list=ls()) library(foreign) - +source("data-raw/listing_duplicated_columns.r") # Preparing the data ----------------------------------------------------------- -brfarmers <- read.dta("data-raw/brfarmers.dta") +brfarmers <- read.dta("data-raw/bf_v2.dta") + +listing_duplicated_columns(brfarmers) +# brfarmers <- subset(brfarmers, select = c(-ado)) + save(brfarmers,file = "data/brfarmers.rdata", compress = "xz") diff --git a/data-raw/brfarmersDiffNet.R b/data-raw/brfarmersDiffNet.R index 74a4eb8..6801eec 100644 --- a/data-raw/brfarmersDiffNet.R +++ b/data-raw/brfarmersDiffNet.R @@ -2,7 +2,8 @@ rm(list=ls()) library(foreign) # Preparing the data ----------------------------------------------------------- -brfarmers <- read.dta("data-raw/brfarmers.dta") +# brfarmers <- read.dta("data-raw/brfarmers.dta") +load("data/brfarmers.rdata") # Adding factors diff --git a/data-raw/kfamily.R b/data-raw/kfamily.R index a08bf3d..9fc8e3f 100644 --- a/data-raw/kfamily.R +++ b/data-raw/kfamily.R @@ -1,7 +1,202 @@ rm(list=ls()) library(foreign) +source("data-raw/listing_duplicated_columns.r") +kfamily <- read.dta("data-raw/kfp_v3_labels_fixed.dta", convert.factors = FALSE) -kfamily <- read.dta("data-raw/kfp_v3_labels_fixed.dta") -save(kfamily,file = "data/kfamily.rdata", +# [,1] [,2] +# "village" "area1" +# "village" "area2" +# "village" "area3" +# "village" "area4" +# "village" "area5" +# "village" "area6" +# "village" "area7" +# "village" "commun" +# "id" "id1" +# "id" "id2" +# "id" "id3" +# "id" "id4" +# "id" "id5" +# "id" "id6" +# "id" "id7" +# "recno1" "studno1" +# "recno1" "studno2" +# "recno1" "studno4" +# "recno1" "studno5" +# "recno1" "studno6" +# "recno1" "studno7" +# "studno1" "studno2" +# "studno1" "studno4" +# "studno1" "studno5" +# "studno1" "studno6" +# "studno1" "studno7" +# "area1" "area2" +# "area1" "area3" +# "area1" "area4" +# "area1" "area5" +# "area1" "area6" +# "area1" "area7" +# "area1" "commun" +# "id1" "id2" +# "id1" "id3" +# "id1" "id4" +# "id1" "id5" +# "id1" "id6" +# "id1" "id7" +# "studno2" "studno4" +# "studno2" "studno5" +# "studno2" "studno6" +# "studno2" "studno7" +# "area2" "area3" +# "area2" "area4" +# "area2" "area5" +# "area2" "area6" +# "area2" "area7" +# "area2" "commun" +# "id2" "id3" +# "id2" "id4" +# "id2" "id5" +# "id2" "id6" +# "id2" "id7" +# "area3" "area4" +# "area3" "area5" +# "area3" "area6" +# "area3" "area7" +# "area3" "commun" +# "id3" "id4" +# "id3" "id5" +# "id3" "id6" +# "id3" "id7" +# "studno4" "studno5" +# "studno4" "studno6" +# "studno4" "studno7" +# "area4" "area5" +# "area4" "area6" +# "area4" "area7" +# "area4" "commun" +# "id4" "id5" +# "id4" "id6" +# "id4" "id7" +# "studno5" "studno6" +# "studno5" "studno7" +# "area5" "area6" +# "area5" "area7" +# "area5" "commun" +# "id5" "id6" +# "id5" "id7" +# "studno6" "studno7" +# "area6" "area7" +# "area6" "commun" +# "id6" "id7" +# "area7" "commun" +# "awe2t9" "awe2t10" +# "awe2t9" "awe2t12" +# "awe3t9" "awe3t10" +# "awe3t9" "awe3t11" +# "awe3t9" "awe3t12" +# "awe2t10" "awe2t12" +# "awe3t10" "awe3t11" +# "awe3t10" "awe3t12" +# "awe3t11" "awe3t12" +# "ado" "toa" + +# All these are duplicated +toremove <- c("area1", +"area2" , +"area3" , +"area4" , +"area5" , +"area6" , +"area7" , +"commun" , +"id1" , +"id2" , +"id3" , +"id4" , +"id5" , +"id6" , +"id7" , +"studno1", +"studno2", +"studno4", +"studno5", +"studno6", +"studno7", +"studno2", +"studno4", +"studno5", +"studno6", +"studno7", +"area2" , +"area3" , +"area4" , +"area5" , +"area6" , +"area7" , +"commun" , +"id2" , +"id3" , +"id4" , +"id5" , +"id6" , +"id7" , +"studno4", +"studno5", +"studno6", +"studno7", +"area3" , +"area4" , +"area5" , +"area6" , +"area7" , +"commun" , +"id3" , +"id4" , +"id5" , +"id6" , +"id7" , +"area4" , +"area5" , +"area6" , +"area7" , +"commun" , +"id4" , +"id5" , +"id6" , +"id7" , +"studno5", +"studno6", +"studno7", +"area5" , +"area6" , +"area7" , +"commun" , +"id5" , +"id6" , +"id7" , +"studno6", +"studno7", +"area6" , +"area7" , +"commun" , +"id6" , +"id7" , +"studno7", +"area7" , +"commun" , +"id7" , +"commun" , +"awe2t10", +"awe2t12", +"awe3t10", +"awe3t11", +"awe3t12", +"awe2t12", +"awe3t11", +"awe3t12", +"awe3t12", "ado") + +# kfamily <- kfamily[,setdiff(colnames(kfamily), toremove)] +save(kfamily, file = "data/kfamily.rdata", compress = "xz") diff --git a/data-raw/kfamilyDiffNet.R b/data-raw/kfamilyDiffNet.R index 216aab8..4fa881c 100644 --- a/data-raw/kfamilyDiffNet.R +++ b/data-raw/kfamilyDiffNet.R @@ -2,7 +2,8 @@ rm(list=ls()) library(foreign) -kfamily <- read.dta("data-raw/kfp_v3_labels_fixed.dta") +# kfamily <- read.dta("data-raw/kfp_v3_labels_fixed.dta") +load("data/kfamily.rdata") # Subsetting netvars <- names(kfamily)[grepl("^net", names(kfamily))] diff --git a/data-raw/listing_duplicated_columns.r b/data-raw/listing_duplicated_columns.r new file mode 100644 index 0000000..e721771 --- /dev/null +++ b/data-raw/listing_duplicated_columns.r @@ -0,0 +1,21 @@ +# This script checks which variables can be repeated... +listing_duplicated_columns <- function(x) { + + # Fixing factors to strings + x <- data.frame(lapply(x, function(y) + if (is.factor(y)) as.character(y) else y + ), stringsAsFactors = FALSE) + + k <- ncol(x) + vnames <- colnames(x) + ans <- NULL + for (i in 1L:ncol(x)) + for (j in i:ncol(x)) { + if (i == j) next + if (all(x[,i] == x[,j], na.rm = TRUE)) + ans <- c(ans, list(c(vnames[c(i,j)]))) + } + + do.call(rbind, ans) +} + diff --git a/data-raw/medInnovations.R b/data-raw/medInnovations.R index cf623c4..c8dbd87 100644 --- a/data-raw/medInnovations.R +++ b/data-raw/medInnovations.R @@ -1,8 +1,23 @@ rm(list=ls()) library(foreign) +source("data-raw/listing_duplicated_columns.r") + # Preparing the data ----------------------------------------------------------- medInnovations <- read.dta("data-raw/mi_v2.dta") +# > listing_duplicated_columns(medInnovations) +# [,1] [,2] +# [1,] "city" "commun" +# [2,] "detail" "detail2" +# [3,] "ado" "adopt" +# [4,] "ado" "toa" +# [5,] "adopt" "toa" +# medInnovations <- medInnovations[ +# , +# setdiff( +# colnames(medInnovations), +# c("commun", "detail2", "adopt", "ado")) +# ] save(medInnovations, file="data/medInnovations.rdata", compress = "xz") diff --git a/data/brfarmers.rdata b/data/brfarmers.rdata index 09430ce..868544d 100644 Binary files a/data/brfarmers.rdata and b/data/brfarmers.rdata differ diff --git a/data/brfarmersDiffNet.rdata b/data/brfarmersDiffNet.rdata index 6e79440..4a570c6 100644 Binary files a/data/brfarmersDiffNet.rdata and b/data/brfarmersDiffNet.rdata differ diff --git a/data/kfamily.rdata b/data/kfamily.rdata index 917d6c2..461a8ab 100644 Binary files a/data/kfamily.rdata and b/data/kfamily.rdata differ diff --git a/data/kfamilyDiffNet.rdata b/data/kfamilyDiffNet.rdata index 5150870..628c5c4 100644 Binary files a/data/kfamilyDiffNet.rdata and b/data/kfamilyDiffNet.rdata differ diff --git a/data/medInnovations.rdata b/data/medInnovations.rdata index 0402b0d..24f848b 100644 Binary files a/data/medInnovations.rdata and b/data/medInnovations.rdata differ diff --git a/man/diffusionMap.Rd b/man/diffusionMap.Rd index aba6ef2..7e25d10 100644 --- a/man/diffusionMap.Rd +++ b/man/diffusionMap.Rd @@ -94,6 +94,7 @@ which basically maps \code{x} to a fix length sequence of numbers such that # Example with a random graph -------------------------------------------------- +\dontrun{ set.seed(1231) # Random scale-free diffusion network @@ -120,6 +121,7 @@ par(mfrow=c(1,1)) mtext("Both networks have the same distribution on times of adoption", 1, outer = TRUE) par(oldpar) +} # Example with Brazilian Farmers -------------------------------------------- \dontrun{ diff --git a/man/edgelist_to_adjmat.Rd b/man/edgelist_to_adjmat.Rd index 89be0fa..89dd136 100644 --- a/man/edgelist_to_adjmat.Rd +++ b/man/edgelist_to_adjmat.Rd @@ -96,7 +96,7 @@ correctly encoded, so when going back (using \code{edgelist_to_adjmat}) # Base data set.seed(123) n <- 5 -edgelist <- rgraph_er(n, as.edgelist=TRUE)[,c("ego","alter")] +edgelist <- rgraph_er(n, as.edgelist=TRUE, p=.2)[,c("ego","alter")] times <- sample.int(3, nrow(edgelist), replace=TRUE) w <- abs(rnorm(nrow(edgelist))) diff --git a/man/isolated.Rd b/man/isolated.Rd index 7b6682e..00d2087 100644 --- a/man/isolated.Rd +++ b/man/isolated.Rd @@ -5,14 +5,18 @@ \alias{drop_isolated} \title{Find and remove isolated vertices} \usage{ -isolated(graph, undirected = getOption("diffnet.undirected")) +isolated(graph, undirected = getOption("diffnet.undirected", FALSE), + self = getOption("diffnet.self", FALSE)) -drop_isolated(graph, undirected = getOption("diffnet.undirected")) +drop_isolated(graph, undirected = getOption("diffnet.undirected", FALSE), + self = getOption("diffnet.self", FALSE)) } \arguments{ \item{graph}{Any class of accepted graph format (see \code{\link{netdiffuseR-graphs}}).} \item{undirected}{Logical scalar. When \code{TRUE} only the lower triangle of the adjacency matrix will considered (faster).} + +\item{self}{Logical scalar. When \code{TRUE} autolinks (loops, self edges) are allowed (see details).} } \value{ When \code{graph} is an adjacency matrix: diff --git a/man/rdiffnet.Rd b/man/rdiffnet.Rd index 6ee0f81..79fb56b 100644 --- a/man/rdiffnet.Rd +++ b/man/rdiffnet.Rd @@ -6,11 +6,9 @@ \usage{ rdiffnet(n, t, seed.nodes = "random", seed.p.adopt = 0.05, seed.graph = "scale-free", rgraph.args = list(), rewire = TRUE, - rewire.args = list(p = 0.1, undirected = getOption("diffnet.undirected", - FALSE), self = getOption("diffnet.self", FALSE)), - threshold.dist = function(x) runif(1), exposure.args = list(outgoing = - TRUE, valued = getOption("diffnet.valued", FALSE), normalized = TRUE), - name = "A diffusion network", behavior = "Random contagion") + rewire.args = list(), threshold.dist = function(x) runif(1), + exposure.args = list(), name = "A diffusion network", + behavior = "Random contagion") } \arguments{ \item{n}{Integer scalar. Number of vertices.} @@ -97,6 +95,22 @@ By default sets the threshold to be random for each node in the graph. If \code{seed.graph} is provided, no random graph is generated and the simulation is applied using that graph instead. + +\code{rewire.args} has the following default options: + +\tabular{ll}{ + \code{p} \tab \code{.1} \cr + \code{undirected} \tab \code{getOption("diffnet.undirected", FALSE)} \cr + \code{self} \tab \code{getOption("diffnet.self", FALSE)} +} + +\code{exposure.args} has the following default options: + +\tabular{ll}{ + \code{outgoing} \tab \code{TRUE} \cr + \code{valued} \tab \code{getOption("diffnet.valued", FALSE)} \cr + \code{normalized} \tab \code{TRUE} +} } \examples{ # Asimple example ----------------------------------------------------------- @@ -113,6 +127,7 @@ y <- rdiffnet(100, 10, threshold.dist=function(x) 1, newMI <- rdiffnet(seed.graph = medInnovationsDiffNet$graph, threshold.dist = threshold(medInnovationsDiffNet), rewire=FALSE) + } \seealso{ Other simulation functions: \code{\link{permute_graph}}, diff --git a/man/rgraph_er.Rd b/man/rgraph_er.Rd index 08fe85b..d9c991c 100644 --- a/man/rgraph_er.Rd +++ b/man/rgraph_er.Rd @@ -5,7 +5,7 @@ \alias{bernoulli} \title{Erdos-Renyi model} \usage{ -rgraph_er(n = 10, t = 1, p = 0.3, +rgraph_er(n = 10, t = 1, p = 0.01, undirected = getOption("diffnet.undirected"), weighted = FALSE, self = getOption("diffnet.self"), as.edgelist = FALSE) } diff --git a/netdiffuseR.Rproj b/netdiffuseR.Rproj index 64565bc..dd8cb83 100755 --- a/netdiffuseR.Rproj +++ b/netdiffuseR.Rproj @@ -18,5 +18,5 @@ StripTrailingWhitespace: Yes BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source -PackageCheckArgs: --as-cran +PackageCheckArgs: --as-cran --no-vignettes PackageRoxygenize: rd,collate,namespace diff --git a/next_release.md b/next_release.md index df1aae5..d7287db 100644 --- a/next_release.md +++ b/next_release.md @@ -9,8 +9,8 @@ The following document details expectations for the comming versions. There is n - Review manuals: Description of arguments and name of the functions. - ~~Aliases creation: `select_egoalter` `table_...`~~ - New meta on the diffnet class: - * name: 'A diffnet network' - * description 'Diffnet network with no description' + * ~~name: 'A diffnet network'~~ + * ~~description 'Diffnet network with no description'~~ * timestamp (maybe auto update) 'DATE' * author: 'user' * netdiffuseR.version: 1.16.6 @@ -27,7 +27,7 @@ The following document details expectations for the comming versions. There is n ## Developing -- `diffnet_to_networkDynamic`, `networkDynamic_to_diffnet`. Need to reach out the author of Carter Butts: Is there any way to access networkDynamic objects formal definition?? +- ~~`diffnet_to_networkDynamic`, `networkDynamic_to_diffnet`. Need to reach out the author of Carter Butts: Is there any way to access networkDynamic objects formal definition??~~ - ~~`rewire_dgr_preserve`: A brief comparison on igraph and netdiffuseR rewiring algorithms shows that igraph has no significan speed improvement in small-medium graphs. This may be due to having a similar rewiring algorithm. The dgr preserve should work in a similar fashion and should incorporate the call to `std::remove` method.~~ diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 33edab1..d67a9d2 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -6,19 +6,6 @@ using namespace Rcpp; -// toa_mat_cpp -List toa_mat_cpp(const IntegerVector& year, int t0, int t1); -RcppExport SEXP _netdiffuseR_toa_mat_cpp(SEXP yearSEXP, SEXP t0SEXP, SEXP t1SEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const IntegerVector& >::type year(yearSEXP); - Rcpp::traits::input_parameter< int >::type t0(t0SEXP); - Rcpp::traits::input_parameter< int >::type t1(t1SEXP); - rcpp_result_gen = Rcpp::wrap(toa_mat_cpp(year, t0, t1)); - return rcpp_result_gen; -END_RCPP -} // edgelist_to_adjmat_cpp arma::sp_mat edgelist_to_adjmat_cpp(const arma::mat& edgelist, NumericVector weights, int n, bool undirected, bool self, bool multiple); RcppExport SEXP _netdiffuseR_edgelist_to_adjmat_cpp(SEXP edgelistSEXP, SEXP weightsSEXP, SEXP nSEXP, SEXP undirectedSEXP, SEXP selfSEXP, SEXP multipleSEXP) { @@ -58,31 +45,6 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } -// isolated_cpp -arma::icolvec isolated_cpp(const arma::sp_mat& adjmat, bool undirected); -RcppExport SEXP _netdiffuseR_isolated_cpp(SEXP adjmatSEXP, SEXP undirectedSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const arma::sp_mat& >::type adjmat(adjmatSEXP); - Rcpp::traits::input_parameter< bool >::type undirected(undirectedSEXP); - rcpp_result_gen = Rcpp::wrap(isolated_cpp(adjmat, undirected)); - return rcpp_result_gen; -END_RCPP -} -// drop_isolated_cpp -arma::sp_mat drop_isolated_cpp(const arma::sp_mat& adjmat, arma::icolvec isolated, bool undirected); -RcppExport SEXP _netdiffuseR_drop_isolated_cpp(SEXP adjmatSEXP, SEXP isolatedSEXP, SEXP undirectedSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const arma::sp_mat& >::type adjmat(adjmatSEXP); - Rcpp::traits::input_parameter< arma::icolvec >::type isolated(isolatedSEXP); - Rcpp::traits::input_parameter< bool >::type undirected(undirectedSEXP); - rcpp_result_gen = Rcpp::wrap(drop_isolated_cpp(adjmat, isolated, undirected)); - return rcpp_result_gen; -END_RCPP -} // egonet_attrs_cpp List egonet_attrs_cpp(const arma::sp_mat& graph, const arma::uvec V, bool outer, bool self, bool valued); RcppExport SEXP _netdiffuseR_egonet_attrs_cpp(SEXP graphSEXP, SEXP VSEXP, SEXP outerSEXP, SEXP selfSEXP, SEXP valuedSEXP) { @@ -163,17 +125,6 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } -// sparse_indexes -arma::umat sparse_indexes(const arma::sp_mat& mat); -RcppExport SEXP _netdiffuseR_sparse_indexes(SEXP matSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const arma::sp_mat& >::type mat(matSEXP); - rcpp_result_gen = Rcpp::wrap(sparse_indexes(mat)); - return rcpp_result_gen; -END_RCPP -} // angle double angle(double x0, double y0, double x1, double y1); RcppExport SEXP _netdiffuseR_angle(SEXP x0SEXP, SEXP y0SEXP, SEXP x1SEXP, SEXP y1SEXP) { @@ -584,18 +535,14 @@ END_RCPP } static const R_CallMethodDef CallEntries[] = { - {"_netdiffuseR_toa_mat_cpp", (DL_FUNC) &_netdiffuseR_toa_mat_cpp, 3}, {"_netdiffuseR_edgelist_to_adjmat_cpp", (DL_FUNC) &_netdiffuseR_edgelist_to_adjmat_cpp, 6}, {"_netdiffuseR_adjmat_to_edgelist_cpp", (DL_FUNC) &_netdiffuseR_adjmat_to_edgelist_cpp, 2}, {"_netdiffuseR_toa_diff_cpp", (DL_FUNC) &_netdiffuseR_toa_diff_cpp, 1}, - {"_netdiffuseR_isolated_cpp", (DL_FUNC) &_netdiffuseR_isolated_cpp, 2}, - {"_netdiffuseR_drop_isolated_cpp", (DL_FUNC) &_netdiffuseR_drop_isolated_cpp, 3}, {"_netdiffuseR_egonet_attrs_cpp", (DL_FUNC) &_netdiffuseR_egonet_attrs_cpp, 5}, {"_netdiffuseR_approx_geodesicCpp", (DL_FUNC) &_netdiffuseR_approx_geodesicCpp, 3}, {"_netdiffuseR_infection_cpp", (DL_FUNC) &_netdiffuseR_infection_cpp, 9}, {"_netdiffuseR_susceptibility_cpp", (DL_FUNC) &_netdiffuseR_susceptibility_cpp, 9}, {"_netdiffuseR_select_egoalter_cpp", (DL_FUNC) &_netdiffuseR_select_egoalter_cpp, 4}, - {"_netdiffuseR_sparse_indexes", (DL_FUNC) &_netdiffuseR_sparse_indexes, 1}, {"_netdiffuseR_angle", (DL_FUNC) &_netdiffuseR_angle, 4}, {"_netdiffuseR_sp_trimatl", (DL_FUNC) &_netdiffuseR_sp_trimatl, 1}, {"_netdiffuseR_sp_diag", (DL_FUNC) &_netdiffuseR_sp_diag, 2}, diff --git a/src/adjmat.cpp b/src/adjmat.cpp index 726e742..0990ff5 100644 --- a/src/adjmat.cpp +++ b/src/adjmat.cpp @@ -16,32 +16,6 @@ using namespace Rcpp; -// [[Rcpp::export]] -List toa_mat_cpp(const IntegerVector & year, int t0, int t1) { - - // Pin down NAs - LogicalVector isna = is_na(year); - - // Measuring time - int n = year.size(); - - // Creating output - List out(2); - arma::mat adopt(n,t1 - t0 + 1, arma::fill::zeros); - - for(int i=0;i cumadopt - Adopt_mat1 -> adopt - */ - return List::create(_["adopt"]=adopt, _["cumadopt"]=cumadopt); -} - // [[Rcpp::export]] arma::sp_mat edgelist_to_adjmat_cpp( const arma::mat & edgelist, @@ -103,14 +77,13 @@ arma::mat adjmat_to_edgelist_cpp( const arma::sp_mat & adjmat, bool undirected = true) { - arma::umat coords = sparse_indexes(adjmat); - int m = coords.n_rows; + unsigned int m = adjmat.n_nonzero, i = 0u; arma::mat edgelist(m, 3); - for (int i=0;i using namespace Rcpp; -// Returns a M x 2 matrix (M: # of non-zero elements) with the set of coordinates -// of the non-zero elements of an sparse matrix. Indices are from 0 to (n-1) -// [[Rcpp::export]] -arma::umat sparse_indexes(const arma::sp_mat & mat) { - - int n = mat.n_nonzero; - arma::umat indices(n,2); - - // If the matrix is empty (which makes no sense) - if (!n) return indices; - - // More efficient implementation - arma::sp_mat::const_iterator begin = mat.begin(); - arma::sp_mat::const_iterator end = mat.end(); - - int i = 0; - for (arma::sp_mat::const_iterator it = begin; it != end; ++it) { - indices.at(i, 0) = it.row(); - indices.at(i++, 1) = it.col(); - } - - // return indices; - return indices; -} - // I ) (x(i) < x(j)) & (y(i) < y(j)) = + Works fine iff // II ) (x(i) > x(j)) & (y(i) < y(j)) = - must add pi // III) (x(i) > x(j)) & (y(i) > y(j)) = + diff --git a/src/netdiffuser_extra.h b/src/netdiffuser_extra.h index 455b3fd..6430f31 100644 --- a/src/netdiffuser_extra.h +++ b/src/netdiffuser_extra.h @@ -9,8 +9,6 @@ using namespace Rcpp; -arma::umat sparse_indexes(const arma::sp_mat & mat); - double angle(double x0, double y0, double x1, double y1); arma::sp_mat sp_trimatl(const arma::sp_mat & x); diff --git a/src/plot.cpp b/src/plot.cpp index baa392b..4747829 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -245,14 +245,10 @@ NumericMatrix edges_coords( yexpand = yexpand * (dev[0]/dev[1]); - // The the filled elements of the graph - arma::umat indexes = sparse_indexes(graph); + for(arma::sp_mat::const_iterator it = graph.begin(); it != graph.end(); it++) { - // for(int i=0;i p) continue; // Indexes - int j = indexes.at(i, 0); - int k = indexes.at(i, 1); + int j = it.row(); + int k = it.col(); // In the case of undirected graphs, we only modify the lower triangle // The upper triangle part will be rewritten during the rand. @@ -200,8 +201,22 @@ arma::sp_mat rewire_swap( // Getting the indexes arma::umat indexes(graph.n_nonzero, 2); - if (undirected) indexes = sparse_indexes(sp_trimatl(newgraph)); - else indexes = sparse_indexes(newgraph); + unsigned int m = 0; + for (arma::sp_mat::const_iterator it = newgraph.begin(); it != newgraph.end(); it++) { + + // Checking cases + if (!self && (it.row() == it.col())) continue; + else if (undirected && (it.row() < it.col())) continue; + + // Filling the matrix + indexes.at(m,0) = it.row(); + indexes.at(m++,1) = it.col(); + + } + + // Shedding rows + if (m < indexes.n_rows) + indexes.shed_rows(m, indexes.n_rows - 1u); // double dens = graph.n_nonzero/(graph.n_cols*graph.n_cols); int s = 0; @@ -343,12 +358,10 @@ set.seed(1133) x <- barabasi.game(1e4) y <- as_adj(x) -ind <- netdiffuseR:::sparse_indexes(y) microbenchmark( ig = rewire(x, keeping_degseq(niter = 100)), nd = netdiffuseR:::rewire_swap(y, 100), - # nd_fast = netdiffuseR:::rewire_swap_fast(y, ind, 100), unit="relative" ) diff --git a/tests/testthat/test-adjmat.R b/tests/testthat/test-adjmat.R index cd3e4d3..bac7212 100644 --- a/tests/testthat/test-adjmat.R +++ b/tests/testthat/test-adjmat.R @@ -103,7 +103,7 @@ context("Time of Adoption (toa_mat, toa_dif)") times <- c(2001L, 2004L, 2003L, 2008L) graph <- lapply(2001:2008, function(x) rgraph_er(4)) -diffnet <- as_diffnet(graph, times) +diffnet <- new_diffnet(graph, times) test_that("Should warn about -times- not been integer", { expect_warning(toa_mat(as.numeric(times)), "will be coersed to integer") @@ -171,17 +171,16 @@ test_that("Finding isolated nodes", { iso23[c(2,3),1:4] <- 0 iso23[1:4,c(2,3)] <- 0 - expect_equal(which(isolated(iso2)==1), 2, info = "only one (dgCMatrix)") - expect_equal(which(isolated(iso23)==1), c(2,3), info = "two (dgCMatrix)") - expect_equal(which(isolated(as.matrix(iso2))==1), 2, info = "only one (matrix)") - expect_equal(which(isolated(as.matrix(iso23))==1), c(2,3), info = "two (matrix)") + expect_equal(which(isolated(iso2)), c(2,3), info = "only one (dgCMatrix)") + expect_equal(which(isolated(iso23)), 2:4, info = "two (dgCMatrix)") # Test with sparse matrix - iso2 <- as(iso2, "dgCMatrix") - iso23 <- as(iso23, "dgCMatrix") + iso2 <- methods::as(iso2, "dgCMatrix") + iso23 <- methods::as(iso23, "dgCMatrix") + + expect_equal(which(isolated(iso2)), c(2,3), info = "only one (dgCMatrix)") + expect_equal(which(isolated(iso23)), 2:4, info = "two (dgCMatrix)") - expect_equal(which(isolated(iso2)==1), 2, info = "only one (array)") - expect_equal(which(isolated(iso23)==1), c(2,3), info = "two (array)") # Dynamic graphs ------------------------------------------------------------- @@ -192,15 +191,11 @@ test_that("Finding isolated nodes", { iso23 <- lapply(dynadjmat, "[<-", i=c(2,3), j=1:4, value=0) iso23 <- lapply(iso23, "[<-", i=1:4, j=c(2,3), value=0) - expect_equal(which(isolated(iso2)$isolated==1), 2, info = "only one (list)") - expect_equal(which(isolated(iso23)$isolated==1), c(2,3), info = "two (list)") + expect_equal(which(isolated(iso2)), 2:3, info = "only one (list)") + expect_equal(which(isolated(iso23)), 2:4, info = "two (list)") - # Test with array - iso2 <- array(unlist(lapply(iso2, as.matrix)), dim=c(4,4,3)) - iso23 <- array(unlist(lapply(iso23, as.matrix)), dim=c(4,4,3)) - - expect_equal(which(isolated(iso2)$isolated==1), 2, info = "only one (array)") - expect_equal(which(isolated(iso23)$isolated==1), c(2,3), info = "two (array)") + dn <- new_diffnet(iso23, sample(1:3, 4, TRUE), t0=1, t1=3) + expect_equal(isolated(dn), isolated(iso23)) }) @@ -215,18 +210,13 @@ test_that("Dropping isolated nodes", { iso23[c(2,3),1:4] <- 0 iso23[1:4,c(2,3)] <- 0 - expect_equal(dim(drop_isolated(iso2)), c(3,3)) - expect_equal(dim(drop_isolated(iso23)), c(2,2)) + expect_equal(dim(drop_isolated(iso2)), c(2,2)) + expect_equal(dim(drop_isolated(iso23)), c(1,1)) # Test with sparse matrix iso2 <- as(iso2, "dgCMatrix") iso23 <- as(iso23, "dgCMatrix") - expect_equal(dim(drop_isolated(iso2)), c(3,3), info = "only one (dgCMatrix)") - expect_equal(dim(drop_isolated(iso23)), c(2,2), info = "two (dgCMatrix)") - expect_equal(dim(drop_isolated(as.matrix(iso2))), c(3,3), info = "only one (matrix)") - expect_equal(dim(drop_isolated(as.matrix(iso23))), c(2,2), info = "two (matrix)") - # Dynamic graphs ------------------------------------------------------------- # Test with lists @@ -236,8 +226,8 @@ test_that("Dropping isolated nodes", { iso23 <- lapply(dynadjmat, "[<-", i=c(2,3), j=1:4, value=0) iso23 <- lapply(iso23, "[<-", i=1:4, j=c(2,3), value=0) - expect_equal(dim(drop_isolated(iso2)[[1]]), c(3,3)) - expect_equal(dim(drop_isolated(iso23)[[1]]), c(2,2)) + expect_equal(dim(drop_isolated(iso2)[[1]]), c(2,2)) + expect_equal(dim(drop_isolated(iso23)[[1]]), c(1,1)) # Test with array iso2 <- array(unlist(lapply(iso2, as.matrix)), dim=c(4,4,3), @@ -250,6 +240,6 @@ test_that("Dropping isolated nodes", { c(d[1],d[2], length(x)) } - expect_equal(dim_list(drop_isolated(iso2)), c(3,3,3)) - expect_equal(dim_list(drop_isolated(iso23)), c(2,2,3)) + expect_equal(dim(drop_isolated(iso2)), c(2,2,3)) + expect_equal(dim(drop_isolated(iso23)), c(1,1,3)) }) diff --git a/tests/testthat/test-sparse_indexes.R b/tests/testthat/test-sparse_indexes.R deleted file mode 100644 index 63bc67b..0000000 --- a/tests/testthat/test-sparse_indexes.R +++ /dev/null @@ -1,37 +0,0 @@ -context("Sparse matrices indexing in Cpp") - -test_that("Are we recovering the right coords?", { - set.seed(13131311) - - n <- 10L - N <- 100L - O <- NULL - - # Empty matrix - x0 <- methods::new("dgCMatrix", Dim=c(n,n), p=rep(0L,n+1L)) - for (j in 1L:((n-1L)*2)) { - for (i in 1L:N) { - x1 <- x0 - - # Filling place - x1[sample.int(n*n,j)] <- 1L - - # Getting the indexes - index <- netdiffuseR:::sparse_indexes(x1) + 1L - - # if (!(i %% 10)) print(x) - - # Reconstructing - x2 <- as.matrix(x0) - x2[index] <- 1L - - O <- c(O, identical(as.matrix(x1), x2)) - } - } - - # print(x1) - # print(methods::as(x2, "dgCMatrix")) - - expect_true(all(O)) - -})