Skip to content

Commit 99069a1

Browse files
committed
Sparse matrix
1 parent bcaa4a1 commit 99069a1

19 files changed

+628
-183
lines changed

DESCRIPTION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ Imports:
2525
igraph,
2626
methods,
2727
checkmate,
28-
matrixStats
28+
matrixStats,
29+
sparseMatrixStats
2930
Suggests:
3031
knitr,
3132
rmarkdown,

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ importFrom(checkmate,assert_int)
1414
importFrom(checkmate,assert_integer)
1515
importFrom(checkmate,assert_logical)
1616
importFrom(checkmate,assert_number)
17+
importFrom(checkmate,assert_vector)
1718
importFrom(checkmate,check_matrix)
1819
importFrom(checkmate,check_numeric)
1920
importFrom(checkmate,test_atomic_vector)
@@ -23,4 +24,5 @@ importFrom(igraph,components)
2324
importFrom(igraph,graph_from_adjacency_matrix)
2425
importFrom(matrixStats,colSums2)
2526
importFrom(methods,is)
27+
importFrom(sparseMatrixStats,colAnyNAs)
2628
useDynLib(diffusr)

NEWS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@
4242
* Codecov
4343
* Initial submission to CRAN
4444

45-
# Author
45+
## Author
4646

4747
* Simon Dirmeier <a href="mailto:simon.dirmeier@gmx.de">simon.dirmeier@gmx.de</a>

R/RcppExports.R

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,42 @@ laplacian_ <- function(W) {
1313
.Call('_diffusr_laplacian_', PACKAGE = 'diffusr', W)
1414
}
1515

16+
laplacian_s <- function(W) {
17+
.Call('_diffusr_laplacian_s', PACKAGE = 'diffusr', W)
18+
}
19+
1620
node_degrees_ <- function(W) {
1721
.Call('_diffusr_node_degrees_', PACKAGE = 'diffusr', W)
1822
}
1923

24+
node_degrees_s <- function(W) {
25+
.Call('_diffusr_node_degrees_s', PACKAGE = 'diffusr', W)
26+
}
27+
2028
hub_normalize_ <- function(W) {
2129
.Call('_diffusr_hub_normalize_', PACKAGE = 'diffusr', W)
2230
}
2331

32+
hub_normalize_s <- function(W) {
33+
.Call('_diffusr_hub_normalize_s', PACKAGE = 'diffusr', W)
34+
}
35+
2436
mrwr_ <- function(p0, W, r, thresh, niter, do_analytical) {
2537
.Call('_diffusr_mrwr_', PACKAGE = 'diffusr', p0, W, r, thresh, niter, do_analytical)
2638
}
2739

40+
mrwr_s <- function(p0, W, r, thresh, niter, do_analytical) {
41+
.Call('_diffusr_mrwr_s', PACKAGE = 'diffusr', p0, W, r, thresh, niter, do_analytical)
42+
}
43+
2844
neighbors_ <- function(node_idxs, W, k) {
2945
.Call('_diffusr_neighbors_', PACKAGE = 'diffusr', node_idxs, W, k)
3046
}
3147

48+
neighbors_s <- function(node_idxs, W, k) {
49+
.Call('_diffusr_neighbors_s', PACKAGE = 'diffusr', node_idxs, W, k)
50+
}
51+
3252
# Register entry points for exported C++ functions
3353
methods::setLoadAction(function(ns) {
3454
.Call('_diffusr_RcppExport_registerCCallable', PACKAGE = 'diffusr')

R/diffusr-package.R

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,10 @@
5454
#' @useDynLib diffusr
5555
#'
5656
#' @importFrom Rcpp sourceCpp
57+
#' @importFrom checkmate assert_vector
58+
#' @importFrom sparseMatrixStats colAnyNAs
5759
NULL
60+
61+
.onAttach <- function(libname, pkgname) {
62+
assert_vector(colAnyNAs(matrix(0)))
63+
}

R/mat_util.R

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@
2727
#' @return returns the normalized matrix/vector
2828
#'
2929
#' @importFrom checkmate assert check_matrix test_numeric test_atomic_vector
30-
#' @importFrom matrixStats colSums2
3130
#'
3231
#' @examples
33-
#' W <- matrix(abs(rnorm(10000)), 100, 100)
34-
#' stoch.W <- normalize.stochastic(W)
32+
#' W <- matrix(abs(rnorm(10000)), 100, 100)
33+
#' stoch.W <- normalize.stochastic(W)
3534
normalize.stochastic <- function(obj, ...) {
3635
is_matrix <- FALSE
3736
if (test_numeric(obj, lower = 0, finite = TRUE, any.missing = FALSE,
@@ -53,13 +52,17 @@ normalize.stochastic <- function(obj, ...) {
5352
is_matrix <- TRUE
5453
}
5554
if (is_matrix) {
56-
sums <- colSums2(obj)
55+
sums <- colSums3(obj, !is_matrix)
5756
if (!all(.equals.double(sums, 1, .001))) {
5857
message("normalizing column vectors!")
5958
empt_col_val <- 1.0 / ncol(obj)
6059

6160
obj <- obj / sums[col(obj)]
62-
obj[, which(sums < empt_col_val)] <- 0.00001
61+
# check if need wipe zeros
62+
zeros <- which(sums < empt_col_val)
63+
if (length(zeros)) {
64+
obj[, zeros] <- 0.00001
65+
}
6366
}
6467
} else {
6568
obj <- obj / sum(obj)
@@ -79,12 +82,12 @@ normalize.stochastic <- function(obj, ...) {
7982
#' @importFrom Rcpp sourceCpp
8083
#'
8184
#' @examples
82-
#' W <- matrix(abs(rnorm(10000)), 100, 100)
83-
#' lapl.W <- normalize.laplacian(W)
85+
#' W <- matrix(abs(rnorm(10000)), 100, 100)
86+
#' lapl.W <- normalize.laplacian(W)
8487
normalize.laplacian <- function(obj, ...) {
8588
if (is.dgCMatrix(obj)) {
8689
assert_dgCMatrix(obj)
87-
# TODO: sparse matrix
90+
return(laplacian_s(obj))
8891
} else {
8992
assert(
9093
check_matrix(obj, mode = "numeric", nrows = ncol(obj), ncols = nrow(obj),
@@ -117,7 +120,7 @@ hub.correction <- function(obj) {
117120
n_elements <- nrow(obj)
118121
if (is.dgCMatrix(obj)) {
119122
assert_dgCMatrix(obj)
120-
# TODO: sparse matrix
123+
return(hub_normalize_s(obj))
121124
} else {
122125
assert(
123126
check_matrix(obj, mode = "numeric", min.rows = 3, nrows = n_elements,
@@ -137,3 +140,16 @@ hub.correction <- function(obj) {
137140
comps <- components(adj)
138141
ifelse(length(comps$csize) == 1, TRUE, FALSE)
139142
}
143+
144+
#' @noRd
145+
#' @importFrom matrixStats colSums2
146+
colSums3 <- function(mat, is.sparse = NULL) {
147+
if (is.null(is.sparse)) {
148+
is.sparse <- is.dgCMatrix(mat)
149+
}
150+
if (is.sparse) {
151+
sums <- sparseMatrixStats::colSums2(mat)
152+
} else {
153+
sums <- colSums2(mat)
154+
}
155+
}

R/mrw.R

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
#' \deqn{ P(j | i) = 1 /degree(i) * min(1, degree(j)/degree(j))}
5656
#' \emph{Note that this will not consider edge weights.}
5757
#'
58-
#' @param ergodic.tolerance Tolerance ergodic of the graph.
58+
#' @param allow.ergodic Allow multiple components in a graph.
5959
#'
6060
#' @param return.pt.only Return pt only.
6161
#'
@@ -94,7 +94,7 @@
9494
#'
9595
random.walk <- function(p0, graph, r = 0.5, niter = 1e4, thresh = 1e-4,
9696
do.analytical = FALSE, correct.for.hubs = FALSE,
97-
ergodic.tolerance = FALSE, return.pt.only = FALSE) {
97+
allow.ergodic = FALSE, return.pt.only = FALSE) {
9898
## Check the fucking inputs
9999
assert_number(r, lower = 0, upper = 1, na.ok = FALSE, finite = TRUE,
100100
null.ok = FALSE)
@@ -111,7 +111,6 @@ random.walk <- function(p0, graph, r = 0.5, niter = 1e4, thresh = 1e-4,
111111
if (is.dgCMatrix(graph)) {
112112
assert_dgCMatrix(graph)
113113
sparse <- TRUE
114-
# TODO: sparse matrix
115114
} else {
116115
assert(
117116
test_matrix(graph, mode = "numeric", min.rows = 3, nrows = n_elements,
@@ -142,13 +141,20 @@ random.walk <- function(p0, graph, r = 0.5, niter = 1e4, thresh = 1e-4,
142141
graph <- hub.correction(graph)
143142
}
144143
stoch.graph <- normalize.stochastic(graph)
145-
if ((!ergodic.tolerance) && (!.is.ergodic(stoch.graph))) {
144+
if ((!allow.ergodic) && (!.is.ergodic(stoch.graph))) {
146145
stop(paste("the provided graph has more than one component.",
147146
"It is likely not ergodic."))
148147
}
149148

150-
l <- mrwr_(normalize.stochastic(p0),
151-
stoch.graph, r, thresh, niter, do.analytical)
149+
if (sparse) {
150+
# sparse matrix
151+
l <- mrwr_s(normalize.stochastic(p0),
152+
stoch.graph, r, thresh, niter, do.analytical)
153+
} else {
154+
# dense matrix
155+
l <- mrwr_(normalize.stochastic(p0),
156+
stoch.graph, r, thresh, niter, do.analytical)
157+
}
152158
if (!return.pt.only) {
153159
l <- list(p.inf = l, transition.matrix = stoch.graph)
154160
}

R/neighbors.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ nearest.neighbors <- function(nodes, graph, k = 1L, ...) {
6868
diag(graph) <- 0
6969
if (is.dgCMatrix(graph)) {
7070
assert_dgCMatrix(graph)
71-
# TODO: sparse matrix
71+
neighbors <- neighbors_s(nodes, graph, k)
7272
} else {
7373
assert(
7474
test_matrix(graph, mode = "numeric", min.rows = 3, nrows = n_elements,

inst/include/diffusr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ using Eigen::SparseMatrix;
4646
typedef Eigen::MappedSparseMatrix<double> MSpMat;
4747
typedef Eigen::Map<MatrixXd> MMatrixXd;
4848
typedef Eigen::SparseMatrix<double> SpMat;
49+
typedef Eigen::SparseMatrix<int> SpMati;
4950
typedef Eigen::Map<VectorXd> MVectorXd;

inst/include/diffusr_RcppExports.h

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,32 @@ namespace diffusr {
8888
return Rcpp::as<MatrixXd >(rcpp_result_gen);
8989
}
9090

91-
inline vector<double> node_degrees_(const MatrixXd& W) {
91+
inline MatrixXd laplacian_s(const SpMat& W) {
92+
typedef SEXP(*Ptr_laplacian_s)(SEXP);
93+
static Ptr_laplacian_s p_laplacian_s = NULL;
94+
if (p_laplacian_s == NULL) {
95+
validateSignature("MatrixXd(*laplacian_s)(const SpMat&)");
96+
p_laplacian_s = (Ptr_laplacian_s)R_GetCCallable("diffusr", "_diffusr_laplacian_s");
97+
}
98+
RObject rcpp_result_gen;
99+
{
100+
RNGScope RCPP_rngScope_gen;
101+
rcpp_result_gen = p_laplacian_s(Shield<SEXP>(Rcpp::wrap(W)));
102+
}
103+
if (rcpp_result_gen.inherits("interrupted-error"))
104+
throw Rcpp::internal::InterruptedException();
105+
if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen))
106+
throw Rcpp::LongjumpException(rcpp_result_gen);
107+
if (rcpp_result_gen.inherits("try-error"))
108+
throw Rcpp::exception(Rcpp::as<std::string>(rcpp_result_gen).c_str());
109+
return Rcpp::as<MatrixXd >(rcpp_result_gen);
110+
}
111+
112+
inline VectorXd node_degrees_(const MatrixXd& W) {
92113
typedef SEXP(*Ptr_node_degrees_)(SEXP);
93114
static Ptr_node_degrees_ p_node_degrees_ = NULL;
94115
if (p_node_degrees_ == NULL) {
95-
validateSignature("vector<double>(*node_degrees_)(const MatrixXd&)");
116+
validateSignature("VectorXd(*node_degrees_)(const MatrixXd&)");
96117
p_node_degrees_ = (Ptr_node_degrees_)R_GetCCallable("diffusr", "_diffusr_node_degrees_");
97118
}
98119
RObject rcpp_result_gen;
@@ -106,7 +127,28 @@ namespace diffusr {
106127
throw Rcpp::LongjumpException(rcpp_result_gen);
107128
if (rcpp_result_gen.inherits("try-error"))
108129
throw Rcpp::exception(Rcpp::as<std::string>(rcpp_result_gen).c_str());
109-
return Rcpp::as<vector<double> >(rcpp_result_gen);
130+
return Rcpp::as<VectorXd >(rcpp_result_gen);
131+
}
132+
133+
inline VectorXd node_degrees_s(const MSpMat& W) {
134+
typedef SEXP(*Ptr_node_degrees_s)(SEXP);
135+
static Ptr_node_degrees_s p_node_degrees_s = NULL;
136+
if (p_node_degrees_s == NULL) {
137+
validateSignature("VectorXd(*node_degrees_s)(const MSpMat&)");
138+
p_node_degrees_s = (Ptr_node_degrees_s)R_GetCCallable("diffusr", "_diffusr_node_degrees_s");
139+
}
140+
RObject rcpp_result_gen;
141+
{
142+
RNGScope RCPP_rngScope_gen;
143+
rcpp_result_gen = p_node_degrees_s(Shield<SEXP>(Rcpp::wrap(W)));
144+
}
145+
if (rcpp_result_gen.inherits("interrupted-error"))
146+
throw Rcpp::internal::InterruptedException();
147+
if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen))
148+
throw Rcpp::LongjumpException(rcpp_result_gen);
149+
if (rcpp_result_gen.inherits("try-error"))
150+
throw Rcpp::exception(Rcpp::as<std::string>(rcpp_result_gen).c_str());
151+
return Rcpp::as<VectorXd >(rcpp_result_gen);
110152
}
111153

112154
inline MatrixXd hub_normalize_(const MatrixXd& W) {
@@ -130,6 +172,27 @@ namespace diffusr {
130172
return Rcpp::as<MatrixXd >(rcpp_result_gen);
131173
}
132174

175+
inline MatrixXd hub_normalize_s(const SpMat& W) {
176+
typedef SEXP(*Ptr_hub_normalize_s)(SEXP);
177+
static Ptr_hub_normalize_s p_hub_normalize_s = NULL;
178+
if (p_hub_normalize_s == NULL) {
179+
validateSignature("MatrixXd(*hub_normalize_s)(const SpMat&)");
180+
p_hub_normalize_s = (Ptr_hub_normalize_s)R_GetCCallable("diffusr", "_diffusr_hub_normalize_s");
181+
}
182+
RObject rcpp_result_gen;
183+
{
184+
RNGScope RCPP_rngScope_gen;
185+
rcpp_result_gen = p_hub_normalize_s(Shield<SEXP>(Rcpp::wrap(W)));
186+
}
187+
if (rcpp_result_gen.inherits("interrupted-error"))
188+
throw Rcpp::internal::InterruptedException();
189+
if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen))
190+
throw Rcpp::LongjumpException(rcpp_result_gen);
191+
if (rcpp_result_gen.inherits("try-error"))
192+
throw Rcpp::exception(Rcpp::as<std::string>(rcpp_result_gen).c_str());
193+
return Rcpp::as<MatrixXd >(rcpp_result_gen);
194+
}
195+
133196
inline VectorXd mrwr_(const MatrixXd& p0, const MatrixXd& W, const double r, const double thresh, const int niter, const bool do_analytical) {
134197
typedef SEXP(*Ptr_mrwr_)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP);
135198
static Ptr_mrwr_ p_mrwr_ = NULL;
@@ -151,11 +214,32 @@ namespace diffusr {
151214
return Rcpp::as<VectorXd >(rcpp_result_gen);
152215
}
153216

154-
inline List neighbors_(const vector<int>& node_idxs, const NumericMatrix& W, const int k) {
217+
inline VectorXd mrwr_s(const MatrixXd& p0, const SpMat& W, const double r, const double thresh, const int niter, const bool do_analytical) {
218+
typedef SEXP(*Ptr_mrwr_s)(SEXP,SEXP,SEXP,SEXP,SEXP,SEXP);
219+
static Ptr_mrwr_s p_mrwr_s = NULL;
220+
if (p_mrwr_s == NULL) {
221+
validateSignature("VectorXd(*mrwr_s)(const MatrixXd&,const SpMat&,const double,const double,const int,const bool)");
222+
p_mrwr_s = (Ptr_mrwr_s)R_GetCCallable("diffusr", "_diffusr_mrwr_s");
223+
}
224+
RObject rcpp_result_gen;
225+
{
226+
RNGScope RCPP_rngScope_gen;
227+
rcpp_result_gen = p_mrwr_s(Shield<SEXP>(Rcpp::wrap(p0)), Shield<SEXP>(Rcpp::wrap(W)), Shield<SEXP>(Rcpp::wrap(r)), Shield<SEXP>(Rcpp::wrap(thresh)), Shield<SEXP>(Rcpp::wrap(niter)), Shield<SEXP>(Rcpp::wrap(do_analytical)));
228+
}
229+
if (rcpp_result_gen.inherits("interrupted-error"))
230+
throw Rcpp::internal::InterruptedException();
231+
if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen))
232+
throw Rcpp::LongjumpException(rcpp_result_gen);
233+
if (rcpp_result_gen.inherits("try-error"))
234+
throw Rcpp::exception(Rcpp::as<std::string>(rcpp_result_gen).c_str());
235+
return Rcpp::as<VectorXd >(rcpp_result_gen);
236+
}
237+
238+
inline List neighbors_(const vector<int>& node_idxs, const MatrixXd& W, const int& k) {
155239
typedef SEXP(*Ptr_neighbors_)(SEXP,SEXP,SEXP);
156240
static Ptr_neighbors_ p_neighbors_ = NULL;
157241
if (p_neighbors_ == NULL) {
158-
validateSignature("List(*neighbors_)(const vector<int>&,const NumericMatrix&,const int)");
242+
validateSignature("List(*neighbors_)(const vector<int>&,const MatrixXd&,const int&)");
159243
p_neighbors_ = (Ptr_neighbors_)R_GetCCallable("diffusr", "_diffusr_neighbors_");
160244
}
161245
RObject rcpp_result_gen;
@@ -172,6 +256,27 @@ namespace diffusr {
172256
return Rcpp::as<List >(rcpp_result_gen);
173257
}
174258

259+
inline List neighbors_s(const vector<int>& node_idxs, const MSpMat& W, const int& k) {
260+
typedef SEXP(*Ptr_neighbors_s)(SEXP,SEXP,SEXP);
261+
static Ptr_neighbors_s p_neighbors_s = NULL;
262+
if (p_neighbors_s == NULL) {
263+
validateSignature("List(*neighbors_s)(const vector<int>&,const MSpMat&,const int&)");
264+
p_neighbors_s = (Ptr_neighbors_s)R_GetCCallable("diffusr", "_diffusr_neighbors_s");
265+
}
266+
RObject rcpp_result_gen;
267+
{
268+
RNGScope RCPP_rngScope_gen;
269+
rcpp_result_gen = p_neighbors_s(Shield<SEXP>(Rcpp::wrap(node_idxs)), Shield<SEXP>(Rcpp::wrap(W)), Shield<SEXP>(Rcpp::wrap(k)));
270+
}
271+
if (rcpp_result_gen.inherits("interrupted-error"))
272+
throw Rcpp::internal::InterruptedException();
273+
if (Rcpp::internal::isLongjumpSentinel(rcpp_result_gen))
274+
throw Rcpp::LongjumpException(rcpp_result_gen);
275+
if (rcpp_result_gen.inherits("try-error"))
276+
throw Rcpp::exception(Rcpp::as<std::string>(rcpp_result_gen).c_str());
277+
return Rcpp::as<List >(rcpp_result_gen);
278+
}
279+
175280
}
176281

177282
#endif // RCPP_diffusr_RCPPEXPORTS_H_GEN_

0 commit comments

Comments
 (0)