Skip to content

Commit 4a10d30

Browse files
committed
initial
0 parents  commit 4a10d30

22 files changed

Lines changed: 2190 additions & 0 deletions

.Rbuildignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
^.*\.Rproj$
2+
^\.Rproj\.user$
3+
^\.github$
4+
^LICENSE\.md$

.github/workflows/R-CMD-check.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples
2+
# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
9+
name: R-CMD-check.yaml
10+
11+
permissions: read-all
12+
13+
jobs:
14+
R-CMD-check:
15+
runs-on: ${{ matrix.config.os }}
16+
17+
name: ${{ matrix.config.os }} (${{ matrix.config.r }})
18+
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
config:
23+
- {os: macos-latest, r: 'release'}
24+
- {os: windows-latest, r: 'release'}
25+
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
26+
- {os: ubuntu-latest, r: 'release'}
27+
- {os: ubuntu-latest, r: 'oldrel-1'}
28+
29+
env:
30+
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
31+
R_KEEP_PKG_SOURCE: yes
32+
33+
steps:
34+
- uses: actions/checkout@v4
35+
36+
- uses: r-lib/actions/setup-pandoc@v2
37+
38+
- uses: r-lib/actions/setup-r@v2
39+
with:
40+
r-version: ${{ matrix.config.r }}
41+
http-user-agent: ${{ matrix.config.http-user-agent }}
42+
use-public-rspm: true
43+
44+
- uses: r-lib/actions/setup-r-dependencies@v2
45+
with:
46+
extra-packages: any::rcmdcheck
47+
needs: check
48+
49+
- uses: r-lib/actions/check-r-package@v2
50+
with:
51+
upload-snapshots: true
52+
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
*.Rproj
2+
.DS_Store
3+
.RData
4+
.Rhistory
5+
.Rproj.user
6+
.Ruserdata
7+
.httr-oauth

DESCRIPTION

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
Package: grasps
2+
Type: Package
3+
Title: Groupwise Regularized Adaptive Sparse Precision Solution
4+
Version: 0.1.0
5+
Authors@R: c(
6+
person(given = "Shiying", family = "Xiao",
7+
email = "shiying.xiao@outlook.com",
8+
role = c("aut", "cre"),
9+
comment = c(ORCID = "0000-0002-8846-3258")),
10+
person(given = "Jun", family = "Yan",
11+
email = "jun.yan@uconn.edu",
12+
role = "aut",
13+
comment = c(ORCID = "0000-0003-4401-7296")),
14+
person(given = "Panpan", family = "Zhang",
15+
email = "panpan.zhang@vumc.org",
16+
role = "aut",
17+
comment = c(ORCID = "0000-0002-8211-5930")))
18+
Maintainer: Shiying Xiao <shiying.xiao@outlook.com>
19+
Description: Provides a unified framework for sparse-group regularization and
20+
precision matrix estimation in Gaussian graphical models. It implements
21+
multiple sparse-group penalties, including sparse-group lasso, sparse-group
22+
adaptive lasso, sparse-group SCAD, and sparse-group MCP, and solves them
23+
efficiently using ADMM-based optimization. The package is designed for
24+
high-dimensional network inference where both sparsity and group structure
25+
are present.
26+
License: GPL (>= 3)
27+
URL: https://github.com/Carol-seven/grasps
28+
BugReports: https://github.com/Carol-seven/grasps/issues
29+
Encoding: UTF-8
30+
LazyData: true
31+
Imports: Rcpp, Rdpack
32+
LinkingTo: Rcpp, RcppArmadillo
33+
RoxygenNote: 7.3.3
34+
RdMacros: Rdpack

LICENSE.md

Lines changed: 595 additions & 0 deletions
Large diffs are not rendered by default.

NAMESPACE

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Generated by roxygen2: do not edit by hand
2+
3+
export(sggm)
4+
importFrom(Rcpp,evalCpp)
5+
importFrom(Rdpack,reprompt)
6+
importFrom(stats,cov)
7+
useDynLib(grasps, .registration = TRUE)

R/RcppExports.R

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
2+
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
3+
4+
ADMMsggm <- function(S, group_idx, penalty, diag_ind, diag_grp, diag_include, lambda, alpha, gamma, rho, tau_incr, tau_decr, nu, tol_abs, tol_rel, maxiter) {
5+
.Call(`_grasps_ADMMsggm`, S, group_idx, penalty, diag_ind, diag_grp, diag_include, lambda, alpha, gamma, rho, tau_incr, tau_decr, nu, tol_abs, tol_rel, maxiter)
6+
}
7+
8+
ADMMsggm_CV <- function(X, group_idx, penalty, diag_ind, diag_grp, diag_include, lambdas, alphas, gamma, rho, tau_incr, tau_decr, nu, tol_abs, tol_rel, maxiter, kfold) {
9+
.Call(`_grasps_ADMMsggm_CV`, X, group_idx, penalty, diag_ind, diag_grp, diag_include, lambdas, alphas, gamma, rho, tau_incr, tau_decr, nu, tol_abs, tol_rel, maxiter, kfold)
10+
}
11+
12+
ADMMsggm_IC <- function(S, group_idx, penalty, diag_ind, diag_grp, diag_include, lambdas, alphas, gamma, rho, tau_incr, tau_decr, nu, tol_abs, tol_rel, maxiter, crit, n, ebic_tuning) {
13+
.Call(`_grasps_ADMMsggm_IC`, S, group_idx, penalty, diag_ind, diag_grp, diag_include, lambdas, alphas, gamma, rho, tau_incr, tau_decr, nu, tol_abs, tol_rel, maxiter, crit, n, ebic_tuning)
14+
}
15+
16+
soft_matrix <- function(M, Thres) {
17+
.Call(`_grasps_soft_matrix`, M, Thres)
18+
}
19+

R/grasps-package.R

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#' grasps
2+
#'
3+
#' Groupwise Regularized Adaptive Sparse Precision Solution
4+
#'
5+
#' @docType _PACKAGE
6+
#' @importFrom Rcpp evalCpp
7+
#' @useDynLib grasps, .registration = TRUE
8+
#' @name grasps
9+
#' @noRd
10+
11+
NULL

R/line_search_lambda_max.R

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#' Line search for the sharp upper bound lambda_max
2+
#'
3+
#' @description
4+
#' Given a list of off-diagonal blocks \code{blockList} from the sample
5+
#' covariance (or a related matrix), this routine finds a **sharp**
6+
#' \eqn{\lambda_{\max}} by bisection so that the KKT condition
7+
#' \deqn{\Vert\text{soft}(B, \lambda\alpha)\Vert_F \leq \lambda(1-\alpha)}
8+
#' holds for every block \eqn{B} in \code{blockList}, where
9+
#' \eqn{\text{soft}(\cdot, t)} denotes elementwise soft-thresholding with
10+
#' threshold \eqn{t}.
11+
#'
12+
#' @param blockList A list of numeric matrices where each element is a block
13+
#' used in the group KKT check.
14+
#'
15+
#' @param lambda.safe A numeric scalar representing a safe (but possibly loose)
16+
#' upper bound for \eqn{\lambda_{\max}}. If the value is negative, the search
17+
#' starts from 1.
18+
#'
19+
#' @param alpha A numeric scalar in (0, 1) specifying the mixture weight between
20+
#' the individual (L1) and group (L2) penalties in sparse-group formulations.
21+
#'
22+
#' @param growiter An integer specifying the maximum number of exponential
23+
#' growth steps during the initial search for an admissible upper bound
24+
#' \eqn{\lambda_{\max}}.
25+
#'
26+
#' @param tol A positive numeric scalar specifying the relative tolerance for
27+
#' the bisection stopping rule on the interval width.
28+
#'
29+
#' @param maxiter An integer specifying the maximum number of bisection
30+
#' iterations.
31+
#'
32+
#' @details
33+
#' The procedure first grows an upper bound starting from \code{lambda.safe}
34+
#' (or 1 if that is non-positive), doubling until the KKT check passes or a
35+
#' growth cap is reached, and then performs bisection between the current
36+
#' lower/upper bounds until the interval width is below
37+
#' \code{tol * max(1, lambda_upper)} or \code{maxiter} is hit.
38+
#'
39+
#' @return
40+
#' A numeric scalar representing the bisection-refined upper bound
41+
#' \eqn{\lambda_{\max}}.
42+
#'
43+
#' @noRd
44+
45+
line_search_lambda_max <- function(blockList, lambda.safe, alpha, growiter, tol, maxiter) {
46+
stopifnot(is.list(blockList), length(blockList) > 0, alpha > 0, alpha < 1)
47+
KKTcheck <- function(lambda) {
48+
for (B in blockList) {
49+
Thres <- matrix(lambda*alpha, nrow(B), ncol(B))
50+
if (norm(soft_matrix(B, Thres), "F") > lambda*(1-alpha)+tol) {
51+
return(FALSE)
52+
}
53+
}
54+
return(TRUE)
55+
}
56+
lambda_upper <- if (lambda.safe > 0) lambda.safe else 1
57+
grow <- 0
58+
while (!KKTcheck(lambda_upper) && grow < growiter) {
59+
lambda_upper <- 2 * lambda_upper
60+
grow <- grow + 1
61+
}
62+
lambda_lower <- 0
63+
iter <- 0
64+
while (iter < maxiter && (lambda_upper-lambda_lower) > tol*max(1,lambda_upper)) {
65+
iter <- iter + 1
66+
lambda_mid <- (lambda_lower + lambda_upper) / 2
67+
if (KKTcheck(lambda_mid)) {
68+
lambda_upper <- lambda_mid
69+
} else {
70+
lambda_lower <- lambda_mid
71+
}
72+
}
73+
return(lambda_upper)
74+
}
75+

0 commit comments

Comments
 (0)