Skip to content

Commit 48f2270

Browse files
committed
function blockband
1 parent 5db7f78 commit 48f2270

3 files changed

Lines changed: 150 additions & 0 deletions

File tree

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Generated by roxygen2: do not edit by hand
22

3+
export(blockband)
34
export(gen_sbm_data)
45
export(grasps)
56
importFrom(MASS,mvrnorm)

R/blockband.R

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#' Block-Band Matrix with Group Structure
2+
#'
3+
#' @description
4+
#' Construct a masked precision matrix where entries are kept only within
5+
#' specified group neighborhoods. Optionally generate Gaussian samples from
6+
#' the resulting precision matrix.
7+
#'
8+
#' @param mat A p-by-p precision-like matrix specifying the base matrix to be
9+
#' masked.
10+
#'
11+
#' @param membership An integer vector specifying the group membership.
12+
#' The length of \code{membership} must be consistent with the dimension p.
13+
#'
14+
#' @param within.diag A boolean (default = TRUE) specifying whether within-group
15+
#' blocks keep only diagonal entries (i.e., identity-like structure within each
16+
#' group).
17+
#'
18+
#' @param neighbor.range An integer (default = 1) specifying the neighbor range,
19+
#' where groups whose labels differ by at most \code{neighbor.range} are
20+
#' considered neighbors and kept in the mask.
21+
#'
22+
#' @param group.diag An integer vector (default = NULL) specifying which
23+
#' within-group blocks should keep diagonal-only structure when
24+
#' \code{within.diag = FALSE}.
25+
#'
26+
#' @param n An integer (default = NULL) specifying the sample size for
27+
#' generating Gaussian data from the resulting precision matrix. If \code{NULL},
28+
#' no data are generated.
29+
#'
30+
#' @param seed An integer (default = 1) specifying the random seed for
31+
#' reproducibility.
32+
#'
33+
#' @importFrom MASS mvrnorm
34+
#'
35+
#' @return A list containing:
36+
#' \describe{
37+
#' \item{Omega}{The masked precision matrix.}
38+
#' \item{Sigma}{The covariance matrix, i.e., the inverse of \code{Omega}.}
39+
#' \item{sparsity}{Proportion of zero entries in \code{Omega}.}
40+
#' \item{X}{If \code{n} is not \code{NULL}, an \code{n}-by-\code{p} matrix of
41+
#' Gaussian observations sampled from \eqn{\mathcal{N}(0, \Sigma)}.}
42+
#' \item{membership}{An integer vector specifying the group membership.}
43+
#' }
44+
#'
45+
#' @export
46+
47+
blockband <- function(mat, membership,
48+
within.diag = TRUE, neighbor.range = 1, group.diag = NULL,
49+
n, seed = 1) {
50+
51+
stopifnot(length(membership) == ncol(mat))
52+
53+
## determine which entries to keep: membership within 'neighbor.range'
54+
mask <- abs(outer(membership, membership, `-`)) <= neighbor.range
55+
56+
## adjust within-group blocks
57+
if (within.diag) {
58+
## within-group blocks -> diagonal matrix
59+
block_idx <- split(seq_along(membership), membership)
60+
for (idx in block_idx) {
61+
mask[idx, idx] <- FALSE
62+
diag(mask[idx, idx]) <- TRUE
63+
}
64+
} else {
65+
if (!is.null(group.diag)) {
66+
for (group_idx in group.diag) {
67+
idx <- which(membership == group_idx)
68+
mask[idx, idx] <- FALSE
69+
diag(mask[idx, idx]) <- TRUE
70+
}
71+
}
72+
}
73+
74+
## apply mask to matrix
75+
Omega <- mat * mask
76+
## compute covariance
77+
Sigma <- solve(Omega)
78+
79+
result <- list(Omega = Omega, Sigma = Sigma,
80+
sparsity = sum(Omega == 0) / length(Omega),
81+
membership = membership)
82+
83+
if (!is.null(n)) {
84+
set.seed(seed)
85+
## sample
86+
result$X <- MASS::mvrnorm(n = n, mu = rep(0, ncol(Omega)), Sigma = Sigma)
87+
}
88+
89+
return(result)
90+
}
91+

man/blockband.Rd

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)