├── .Rbuildignore
├── .aspell
└── moma.rds
├── .gitignore
├── CONTRIBUTORS
├── DESCRIPTION
├── LICENSE
├── NAMESPACE
├── R
├── RcppExports.R
├── internals.R
├── logging.R
├── moma-R6.R
├── moma-package.R
├── moma_5Dlist_extractor.R
├── moma_arguments.R
├── moma_expose.R
├── moma_sfcca.R
├── moma_sflda.R
├── moma_sfpca.R
├── moma_solve.R
├── util.R
└── zzz.R
├── README.Rmd
├── README.md
├── _pkgdown.yml
├── docs
├── ISSUE_TEMPLATE.html
├── LICENSE-text.html
├── PULL_REQUEST_TEMPLATE.html
├── SUPPORT.html
├── articles
│ ├── index.html
│ ├── moma-LDA.html
│ ├── moma-PCA.html
│ ├── moma-functional-data-analysis.html
│ ├── moma-functional-data-analysis_files
│ │ └── figure-html
│ │ │ ├── unnamed-chunk-3-1.png
│ │ │ ├── unnamed-chunk-4-1.png
│ │ │ ├── unnamed-chunk-5-1.png
│ │ │ └── unnamed-chunk-7-1.png
│ └── moma-quick-start.html
├── authors.html
├── docsearch.css
├── docsearch.js
├── index.html
├── link.svg
├── pkgdown.css
├── pkgdown.js
├── pkgdown.yml
└── reference
│ ├── CCA_deflation.html
│ ├── LDA_deflation.html
│ ├── MoMA.html
│ ├── PCA_deflation.html
│ ├── cluster.html
│ ├── figures
│ ├── README-usage-ldademo.png
│ ├── moma-formula.svg
│ └── vignettes-pca-demo.png
│ ├── fused_lasso.html
│ ├── group_lasso.html
│ ├── index.html
│ ├── l1_trend_filtering.html
│ ├── lasso.html
│ ├── mcp.html
│ ├── moma_R6.html
│ ├── moma_logging.html
│ ├── moma_pg_settings.html
│ ├── moma_session_info.html
│ ├── moma_sfcca.html
│ ├── moma_sflda.html
│ ├── moma_sfpca.html
│ ├── moma_smoothness.html
│ ├── moma_sparsity_options.html
│ ├── scad.html
│ ├── second_diff_mat.html
│ ├── select_scheme.html
│ ├── slope.html
│ └── sparse_fused_lasso.html
├── inst
└── GIT.HASH
├── man
├── CCA_deflation.Rd
├── LDA_deflation.Rd
├── MoMA.Rd
├── PCA_deflation.Rd
├── cluster.Rd
├── figures
│ ├── README-usage-ldademo.png
│ ├── moma-formula.svg
│ └── vignettes-pca-demo.png
├── fused_lasso.Rd
├── group_lasso.Rd
├── l1_trend_filtering.Rd
├── lasso.Rd
├── mcp.Rd
├── moma_R6.Rd
├── moma_logging.Rd
├── moma_pg_settings.Rd
├── moma_session_info.Rd
├── moma_sfcca.Rd
├── moma_sflda.Rd
├── moma_sfpca.Rd
├── moma_smoothness.Rd
├── moma_sparsity_options.Rd
├── scad.Rd
├── second_diff_mat.Rd
├── select_scheme.Rd
├── slope.Rd
└── sparse_fused_lasso.Rd
├── src
├── Makevars
├── Makevars.win
├── RcppExports.cpp
├── moma.cpp
├── moma.h
├── moma_base.h
├── moma_expose.cpp
├── moma_fivedlist.cpp
├── moma_fivedlist.h
├── moma_heap.cpp
├── moma_heap.h
├── moma_level1.cpp
├── moma_logging.cpp
├── moma_logging.h
├── moma_prox.cpp
├── moma_prox.h
├── moma_prox_flsadp.cpp
├── moma_prox_flsadp.h
├── moma_prox_fusion_util.cpp
├── moma_prox_fusion_util.h
├── moma_prox_l1ft.cpp
├── moma_prox_sortedL1.cpp
├── moma_prox_sortedL1.h
├── moma_solver.cpp
├── moma_solver.h
├── moma_solver_BICsearch.cpp
├── moma_solver_BICsearch.h
└── moma_test_expose.cpp
├── tests
├── testthat.R
└── testthat
│ ├── helper_moma_tests.R
│ ├── test_5Dlist_extractor.R
│ ├── test_BIC.R
│ ├── test_MBG-single_problem.R
│ ├── test_MBG_correctly_sized_result.R
│ ├── test_MGB_BIC.R
│ ├── test_MGB_multirank.R
│ ├── test_argument_extended.R
│ ├── test_arguments.R
│ ├── test_dof.R
│ ├── test_grid.R
│ ├── test_logging.R
│ ├── test_prox_SLOPE.R
│ ├── test_prox_fused_lasso.R
│ ├── test_prox_l1tf.R
│ ├── test_prox_sparse_fused_lasso.R
│ ├── test_prox_sparsity_thresholding.R
│ ├── test_prox_unordered_fusion.R
│ ├── test_sfcca_wrapper.R
│ ├── test_sflda_wrapper.R
│ ├── test_sfpca_wrapper.R
│ ├── test_solve.R
│ └── test_util.R
└── vignettes
├── moma-LDA.Rmd
├── moma-PCA.Rmd
├── moma-functional-data-analysis.Rmd
├── moma-quick-start.Rmd
└── vignettes.bibtex
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^.*\.Rproj$
2 | ^\.Rproj\.user$
3 | ^TODO$
4 | ^ALGORITHM$
5 | vignettes/moma-quick-start_cache/*
6 | vignettes/moma-quick-start_files/*
7 | ^docs$
8 | ^_pkgdown\.yml$
9 | ^.travis\.yml$
10 | .gitignore.deploy
11 | README.Rmd
12 | README.md
13 | figs/*
14 | build_steps.R
15 | ^codecov\.yml$
16 | LICENSE
17 | CONTRIBUTORS
18 | .github/*
19 | .vscode/*
20 |
--------------------------------------------------------------------------------
/.aspell/moma.rds:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/.aspell/moma.rds
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Travis deploy file
2 | deployed*
3 |
4 | # RStudio and R working files
5 | .Rproj.user
6 | .Rhistory
7 | .RData
8 | .Ruserdata
9 | *.Rproj
10 | vignettes/*_cache/
11 | vignettes/*_files/
12 | vignettes/*.R
13 |
14 | # Platform specific compiled files
15 | src/*.gcda
16 | src/*.o
17 | src/*.so
18 | src/*.dll
19 | inst/doc
20 |
21 | # VS Code configuration files
22 | .vscode/*
23 |
24 | # Development scripts
25 | .github/*
26 | script/*
27 | .clang-format
28 | .travis.yml
29 |
--------------------------------------------------------------------------------
/CONTRIBUTORS:
--------------------------------------------------------------------------------
1 | Code Contributions
2 | ===================
3 |
4 | Bug reports and other feedback
5 | ===============================
6 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: MoMA
2 | Title: MoMA - Modern Multivariate Analysis in R
3 | Version: 0.1
4 | Date: 2018-05-07
5 | Authors@R: c(
6 | person("Michael", "Weylandt", email="michael.weylandt@rice.edu", role=c("aut", "cre")),
7 | person("Genevera", "Allen", email="gallen@rice.edu", role="aut"),
8 | person("Luofeng", "Liao", email="luofengl@student.unimelb.edu.au", role="aut"),
9 | person("Nicholas", "Johnson", role = "cph", comment = "src/moma_prox_flsadp.cpp")
10 | )
11 | Description: Unified approach to modern multivariate analysis providing sparse,
12 | smooth, and structured versions of PCA, PLS, LDA, and CCA.
13 | License: GPL (>= 2)
14 | Imports: Rcpp, R6
15 | Suggests:
16 | knitr,
17 | rmarkdown,
18 | testthat,
19 | covr,
20 | devtools,
21 | stringr,
22 | flsa,
23 | cvxclustr,
24 | SLOPE
25 | LinkingTo: Rcpp (>= 0.12.0), RcppArmadillo (>= 0.8.300.1.0)
26 | RoxygenNote: 6.1.1
27 | VignetteBuilder: knitr
28 | URL: https://github.com/DataSlingers/MoMA
29 | BugReports: https://github.com/DataSlingers/MoMA/issues
30 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(moma_cluster)
4 | export(moma_fcca)
5 | export(moma_flda)
6 | export(moma_fpca)
7 | export(moma_fusedlasso)
8 | export(moma_grplasso)
9 | export(moma_l1tf)
10 | export(moma_lasso)
11 | export(moma_logger_level)
12 | export(moma_mcp)
13 | export(moma_pg_settings)
14 | export(moma_scad)
15 | export(moma_scca)
16 | export(moma_session_info)
17 | export(moma_sfcca)
18 | export(moma_sflda)
19 | export(moma_sfpca)
20 | export(moma_slda)
21 | export(moma_slope)
22 | export(moma_smoothness)
23 | export(moma_spca)
24 | export(moma_spfusedlasso)
25 | export(moma_twfcca)
26 | export(moma_twflda)
27 | export(moma_twfpca)
28 | export(moma_twscca)
29 | export(moma_twslda)
30 | export(moma_twspca)
31 | export(second_diff_mat)
32 | importFrom(Rcpp,evalCpp)
33 | importFrom(stats,setNames)
34 | importFrom(utils,packageDescription)
35 | importFrom(utils,sessionInfo)
36 | useDynLib(MoMA)
37 |
--------------------------------------------------------------------------------
/R/RcppExports.R:
--------------------------------------------------------------------------------
1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand
2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
3 |
4 | cpp_moma_multi_rank <- function(X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, rank = 1L) {
5 | .Call('_MoMA_cpp_moma_multi_rank', PACKAGE = 'MoMA', X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, rank)
6 | }
7 |
8 | cpp_moma_grid_search <- function(X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, rank = 1L) {
9 | .Call('_MoMA_cpp_moma_grid_search', PACKAGE = 'MoMA', X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, rank)
10 | }
11 |
12 | cpp_moma_criterion_search <- function(X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, rank = 1L) {
13 | .Call('_MoMA_cpp_moma_criterion_search', PACKAGE = 'MoMA', X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, rank)
14 | }
15 |
16 | cpp_multirank_BIC_grid_search <- function(X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, deflation_scheme = 1L, select_scheme_alpha_u = 0L, select_scheme_alpha_v = 0L, select_scheme_lambda_u = 0L, select_scheme_lambda_v = 0L, max_bic_iter = 5L, rank = 1L) {
17 | .Call('_MoMA_cpp_multirank_BIC_grid_search', PACKAGE = 'MoMA', X, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, deflation_scheme, select_scheme_alpha_u, select_scheme_alpha_v, select_scheme_lambda_u, select_scheme_lambda_v, max_bic_iter, rank)
18 | }
19 |
20 | cca <- function(X, Y, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, deflation_scheme, select_scheme_alpha_u = 0L, select_scheme_alpha_v = 0L, select_scheme_lambda_u = 0L, select_scheme_lambda_v = 0L, max_bic_iter = 5L, rank = 1L) {
21 | .Call('_MoMA_cca', PACKAGE = 'MoMA', X, Y, alpha_u, alpha_v, Omega_u, Omega_v, lambda_u, lambda_v, prox_arg_list_u, prox_arg_list_v, EPS, MAX_ITER, EPS_inner, MAX_ITER_inner, solver, deflation_scheme, select_scheme_alpha_u, select_scheme_alpha_v, select_scheme_lambda_u, select_scheme_lambda_v, max_bic_iter, rank)
22 | }
23 |
24 | moma_set_logger_level_cpp <- function(level) {
25 | invisible(.Call('_MoMA_moma_set_logger_level_cpp', PACKAGE = 'MoMA', level))
26 | }
27 |
28 | moma_get_logger_level_cpp <- function() {
29 | .Call('_MoMA_moma_get_logger_level_cpp', PACKAGE = 'MoMA')
30 | }
31 |
32 | moma_log_cpp <- function(level, x) {
33 | invisible(.Call('_MoMA_moma_log_cpp', PACKAGE = 'MoMA', level, x))
34 | }
35 |
36 | l1tf_diff_mat <- function(m, k) {
37 | .Call('_MoMA_l1tf_diff_mat', PACKAGE = 'MoMA', m, k)
38 | }
39 |
40 | test_prox_lasso <- function(x, l) {
41 | .Call('_MoMA_test_prox_lasso', PACKAGE = 'MoMA', x, l)
42 | }
43 |
44 | test_prox_nnlasso <- function(x, l) {
45 | .Call('_MoMA_test_prox_nnlasso', PACKAGE = 'MoMA', x, l)
46 | }
47 |
48 | test_prox_scad <- function(x, l, gamma = 3.7) {
49 | .Call('_MoMA_test_prox_scad', PACKAGE = 'MoMA', x, l, gamma)
50 | }
51 |
52 | test_prox_scadvec <- function(x, l, gamma = 3.7) {
53 | .Call('_MoMA_test_prox_scadvec', PACKAGE = 'MoMA', x, l, gamma)
54 | }
55 |
56 | test_prox_nnscad <- function(x, l, gamma = 3.7) {
57 | .Call('_MoMA_test_prox_nnscad', PACKAGE = 'MoMA', x, l, gamma)
58 | }
59 |
60 | test_prox_mcp <- function(x, l, gamma = 4) {
61 | .Call('_MoMA_test_prox_mcp', PACKAGE = 'MoMA', x, l, gamma)
62 | }
63 |
64 | test_prox_mcpvec <- function(x, l, gamma = 4) {
65 | .Call('_MoMA_test_prox_mcpvec', PACKAGE = 'MoMA', x, l, gamma)
66 | }
67 |
68 | test_prox_nnmcp <- function(x, l, gamma = 4) {
69 | .Call('_MoMA_test_prox_nnmcp', PACKAGE = 'MoMA', x, l, gamma)
70 | }
71 |
72 | test_prox_grplasso <- function(x, g, l) {
73 | .Call('_MoMA_test_prox_grplasso', PACKAGE = 'MoMA', x, g, l)
74 | }
75 |
76 | test_prox_nngrplasso <- function(x, g, l) {
77 | .Call('_MoMA_test_prox_nngrplasso', PACKAGE = 'MoMA', x, g, l)
78 | }
79 |
80 | test_prox_fusedlassopath <- function(x, l) {
81 | .Call('_MoMA_test_prox_fusedlassopath', PACKAGE = 'MoMA', x, l)
82 | }
83 |
84 | test_prox_fusedlassodp <- function(x, l) {
85 | .Call('_MoMA_test_prox_fusedlassodp', PACKAGE = 'MoMA', x, l)
86 | }
87 |
88 | test_prox_spfusedlasso <- function(x, l, lambda2) {
89 | .Call('_MoMA_test_prox_spfusedlasso', PACKAGE = 'MoMA', x, l, lambda2)
90 | }
91 |
92 | test_prox_fusion <- function(x, l, w, ADMM, acc, prox_eps = 1e-10) {
93 | .Call('_MoMA_test_prox_fusion', PACKAGE = 'MoMA', x, l, w, ADMM, acc, prox_eps)
94 | }
95 |
96 | test_prox_l1gf <- function(x, l, k = 1L) {
97 | .Call('_MoMA_test_prox_l1gf', PACKAGE = 'MoMA', x, l, k)
98 | }
99 |
100 | test_prox_slope <- function(x, l) {
101 | .Call('_MoMA_test_prox_slope', PACKAGE = 'MoMA', x, l)
102 | }
103 |
104 | test_df_orderedfusion <- function(x) {
105 | .Call('_MoMA_test_df_orderedfusion', PACKAGE = 'MoMA', x)
106 | }
107 |
108 | test_df_spfusedlasso <- function(x) {
109 | .Call('_MoMA_test_df_spfusedlasso', PACKAGE = 'MoMA', x)
110 | }
111 |
112 | test_df_l1gf <- function(x, k = 1L) {
113 | .Call('_MoMA_test_df_l1gf', PACKAGE = 'MoMA', x, k)
114 | }
115 |
116 | test_df_grplasso <- function(x, g) {
117 | .Call('_MoMA_test_df_grplasso', PACKAGE = 'MoMA', x, g)
118 | }
119 |
120 | test_BIC <- function(y, y_est, algorithm_string, i_alpha, i_Omega, i_lambda, prox_arg_list, dim, i_EPS = 1e-6, i_MAX_ITER = 1e+3L) {
121 | .Call('_MoMA_test_BIC', PACKAGE = 'MoMA', y, y_est, algorithm_string, i_alpha, i_Omega, i_lambda, prox_arg_list, dim, i_EPS, i_MAX_ITER)
122 | }
123 |
124 |
--------------------------------------------------------------------------------
/R/internals.R:
--------------------------------------------------------------------------------
1 | #' @importFrom utils packageDescription
2 | moma_git_hash <- function() {
3 | pd <- packageDescription("moma")
4 | gh_file <- system.file("GIT.HASH", package = "moma")
5 |
6 | if (!is.null(pd$RemoteSha)) { # devtools install
7 | return(pd$RemoteSha)
8 | } else if (file.exists(gh_file)) {
9 | return(readLines(gh_file))
10 | } else {
11 | NA
12 | }
13 | }
14 |
15 |
16 | #' Session Info used for Bug Reporting
17 | #'
18 | #' A helper function which prints information useful in
19 | #' bug reports.
20 | #'
21 | #' @return None. Called for side-effects (printed to the screen)
22 | #' only.
23 | #' @export
24 | #' @importFrom utils sessionInfo
25 | moma_session_info <- function() {
26 | old_print <- options(max.print = 9999)
27 | on.exit(options(old_print))
28 |
29 | cat("MoMA Git Hash: ", moma_git_hash(), "\n")
30 |
31 | if (requireNamespace("devtools")) {
32 | print(devtools::session_info("moma"))
33 | } else {
34 | print(sessionInfo())
35 | }
36 |
37 | invisible(NULL)
38 | }
39 |
--------------------------------------------------------------------------------
/R/logging.R:
--------------------------------------------------------------------------------
1 | # Logging infrastructure for MoMA
2 |
3 | ## This must be kept consistent with src/moma_logging.h::MoMAoggerLevel
4 | LEVELS <- c(
5 | ERROR = 40,
6 | WARNING = 30,
7 | MESSAGE = 20,
8 | INFO = 10,
9 | DEBUG = 00
10 | )
11 |
12 |
13 | #' MoMA Package Logging Functionality
14 | #'
15 | #' Control the global logging level for the \code{moma} package.
16 | #'
17 | #' @importFrom stats setNames
18 | #' @export
19 | #' @param level The desired new log level. Available levels are \itemize{
20 | #' \item \code{ERROR} - corresponding to \code{base::stop};
21 | #' \item \code{WARNING} - corresponding to \code{base::warning};
22 | #' \item \code{MESSAGE} - corresponding to \code{base::message};
23 | #' \item \code{INFO}; and
24 | #' \item \code{DEBUG.}
25 | #' } If omitted, the log level is not changed (and the current level is still
26 | #' returned invisibly.) See below for details about the different levels.
27 | #' @return The previous log level (invisibly).
28 | #' @rdname moma_logging
29 | #' @aliases moma_logging moma_logger_level
30 | #' @details The \code{moma} package has a multi-level logging system, with a single
31 | #' global log level; (which applies to both \code{R} and \code{C++} level
32 | #' functionality.) the levels are, in decreasing order, \code{ERROR},
33 | #' \code{WARNING}, \code{MESSAGE} (default), \code{INFO}, \code{DEBUG}.
34 | #'
35 | #' To change the amount of output from the \code{moma} package, the
36 | #' \code{moma_logger_level} function can be used to adjust the global
37 | #' log level. The \code{INFO} and \code{DEBUG} levels can be quite verbose
38 | #' and may significantly slow down the package.
39 | moma_logger_level <- function(level = c(
40 | "ERROR",
41 | "WARNING",
42 | "MESSAGE",
43 | "INFO",
44 | "DEBUG"
45 | )) {
46 | LEVELS_REV <- setNames(names(LEVELS), LEVELS)
47 |
48 | old_level <- LEVELS_REV[as.character(moma_get_logger_level_cpp())]
49 | names(old_level) <- NULL
50 |
51 | if (!missing(level)) {
52 | level <- match.arg(level)
53 | moma_set_logger_level_cpp(LEVELS[level])
54 | return(invisible(old_level))
55 | }
56 |
57 | old_level
58 | }
59 |
60 | moma_error <- function(..., call = TRUE) {
61 | msg <- paste(list(...), collapse = "")
62 |
63 | ## Try to add R level calling info
64 | if (identical(call, TRUE)) {
65 | tryCatch({
66 | msg <- paste0(msg, " (Called from ", as.character(as.list(sys.call(-1))[[1]]), ")")
67 | }, error = function(e) {})
68 | } else if (is.character(call)) {
69 | msg <- paste0(msg, " (Called from ", call, ")")
70 | }
71 |
72 | moma_log_cpp(LEVELS["ERROR"], msg)
73 | }
74 |
75 | moma_warning <- function(..., call = TRUE) {
76 | msg <- paste(list(...), collapse = "")
77 |
78 | ## Try to add R level calling info
79 | if (identical(call, TRUE)) {
80 | tryCatch({
81 | msg <- paste0(msg, " (Called from ", as.character(as.list(sys.call(-1))[[1]]), ")")
82 | }, error = function(e) {})
83 | } else if (is.character(call)) {
84 | msg <- paste0(msg, " (Called from ", call, ")")
85 | }
86 |
87 | moma_log_cpp(LEVELS["WARNING"], msg)
88 | }
89 |
90 | moma_message <- function(...) {
91 | msg <- paste(list(...), collapse = "")
92 | moma_log_cpp(LEVELS["MESSAGE"], msg)
93 | }
94 |
95 | moma_info <- function(...) {
96 | msg <- paste(list(...), collapse = "")
97 | moma_log_cpp(LEVELS["INFO"], msg)
98 | }
99 |
100 | moma_debug <- function(...) {
101 | msg <- paste(list(...), collapse = "")
102 | moma_log_cpp(LEVELS["DEBUG"], msg)
103 | }
104 |
--------------------------------------------------------------------------------
/R/moma-package.R:
--------------------------------------------------------------------------------
1 | #' MoMA: Modern Multivariate Analysis in R
2 | #'
3 | #' TODO
4 | #'
5 | #' See the package vignettes for details of the algorithm, as well as
6 | #' comparisons to existing methods.
7 | #'
8 | #' @docType package
9 | #' @name MoMA
10 | #' @useDynLib MoMA
11 | NULL
12 |
13 | ## Importing evalCpp is a hack to ensure that Rcpp is initialized before MoMA
14 | ## and may not be necessary if MoMA adds dependencies on other packages which
15 | ## will in turn initialize Rcpp
16 | ##
17 | ## Failing to have this import leads to a fairly nasty bug where
18 | ## MoMA:::.onAttach() fails and, more often than not, hangs indefinitely
19 | #' @importFrom Rcpp evalCpp
20 | NULL
21 |
--------------------------------------------------------------------------------
/R/moma_5Dlist_extractor.R:
--------------------------------------------------------------------------------
1 | get_5Dlist_elem <- function(x, alpha_u_i, lambda_u_i, alpha_v_i, lambda_v_i, rank_i = 1) {
2 | if (!inherits(x, "MoMA_5D_list")) {
3 | moma_error(sQuote("x"), " should be a ", sQuote("MoMA_5D_list"), " object.")
4 | }
5 | n_alpha_u <- dim(x)[1]
6 | n_lambda_u <- dim(x)[2]
7 | n_alpha_v <- dim(x)[3]
8 | n_lambda_v <- dim(x)[4]
9 | n_rank <- dim(x)[5]
10 |
11 | # NOTE: R index starts from 1
12 | if (
13 | alpha_u_i <= 0 || alpha_u_i > n_alpha_u ||
14 | lambda_u_i <= 0 || lambda_u_i > n_lambda_u ||
15 | alpha_v_i <= 0 || alpha_v_i > n_alpha_v ||
16 | lambda_v_i <= 0 || lambda_v_i > n_lambda_v ||
17 | rank_i <= 0 || rank_i > n_rank
18 | ) {
19 | moma_error(
20 | "Invalid index (", alpha_u_i, ",", lambda_u_i,
21 | ",", alpha_v_i, ",", lambda_v_i, ",", rank_i, "), dim = ",
22 | dim(x)
23 | )
24 | }
25 |
26 | return(x[
27 | rank_i + n_rank * (
28 | lambda_v_i - 1 + n_lambda_v * (
29 | alpha_v_i - 1 + n_alpha_v * (
30 | lambda_u_i - 1 + n_lambda_u * (
31 | alpha_u_i - 1
32 | )
33 | )
34 | )
35 | )
36 | ])
37 | }
38 |
--------------------------------------------------------------------------------
/R/moma_expose.R:
--------------------------------------------------------------------------------
1 | moma_svd <- function(
2 | X,
3 | u_sparsity = empty(), v_sparsity = empty(), lambda_u = 0, lambda_v = 0, # lambda_u/_v is a vector or scalar
4 | Omega_u = NULL, Omega_v = NULL, alpha_u = 0, alpha_v = 0, # so is alpha_u/_v
5 | pg_settings = moma_pg_settings(),
6 | k = 1, # number of pairs of singular vecters
7 | select = c("gridsearch", "nestedBIC")) {
8 | if (!inherits(alpha_u, c("numeric", "integer")) ||
9 | !inherits(alpha_v, c("numeric", "integer")) ||
10 | !inherits(lambda_u, c("numeric", "integer")) ||
11 | !inherits(lambda_v, c("numeric", "integer"))) {
12 | moma_error(paste0(
13 | "All penalty levels (",
14 | sQuote("lambda_u"), ", ",
15 | sQuote("lambda_v"), ", ",
16 | sQuote("alpha_u"), ", ",
17 | sQuote("alpha_v"),
18 | ") must be numeric."
19 | ))
20 | }
21 |
22 | select <- match.arg(select)
23 | all_para <- c(alpha_u, alpha_v, lambda_u, lambda_v)
24 |
25 | # verify all alphas and lambdas are positive numbers
26 | if (any(all_para < 0) || any(!is.finite(all_para))) {
27 | moma_error(
28 | "All penalty levels (",
29 | sQuote("lambda_u"), ", ",
30 | sQuote("lambda_v"), ", ",
31 | sQuote("alpha_u"), ", ",
32 | sQuote("alpha_v"),
33 | ") must be non-negative numeric."
34 | )
35 | }
36 |
37 | # from scalar to vector
38 | alpha_u <- as.vector(alpha_u)
39 | alpha_v <- as.vector(alpha_v)
40 | lambda_u <- as.vector(lambda_u)
41 | lambda_v <- as.vector(lambda_v)
42 |
43 | if (!is.matrix(X)) {
44 | moma_error("X must be a matrix.")
45 | }
46 | if (any(!is.finite(X))) {
47 | moma_error("X must not have NaN, NA, or Inf.")
48 | }
49 | n <- dim(X)[1]
50 | p <- dim(X)[2]
51 |
52 | # If all of alpha_u, alpha_v, lambda_u, lambda_v are
53 | # a number, we just solve ONE MoMA problem.
54 | is_multiple_para <- length(alpha_u) > 1 ||
55 | length(alpha_v) > 1 ||
56 | length(lambda_u) > 1 ||
57 | length(lambda_v) > 1
58 |
59 | # k must be 1 if alpha_u/v or lambda_u/v is of vector form
60 | if (is_multiple_para && k != 1) {
61 | moma_error("We don't support a range of parameters in finding a rank-k svd")
62 | }
63 |
64 | # Sparsity arguments
65 | # "_moma_sparsity_type" includes all penalty types
66 | if (!inherits(u_sparsity, "_moma_sparsity_type") || !inherits(v_sparsity, "_moma_sparsity_type")) {
67 | moma_error(
68 | "Sparse penalty should be of class ",
69 | sQuote("_moma_sparsity_type"),
70 | ". Try using, for example, `u_sparsity = lasso()`."
71 | )
72 | }
73 |
74 | # PG loop settings
75 | if (!inherits(pg_settings, "moma_pg_settings")) {
76 | moma_error(
77 | "pg_settings penalty should be of class ",
78 | sQuote("moma_pg_settings"),
79 | ". Try using, for example, `pg_settings = moma_pg_settings(MAX_ITER=1e+4)`."
80 | )
81 | }
82 |
83 | # Pack all argument into a list
84 | # First we check the smoothness term argument.
85 | algo_settings_list <- c(
86 | list(
87 | X = X,
88 | lambda_u = lambda_u,
89 | lambda_v = lambda_v,
90 | # smoothness
91 | alpha_u = alpha_u,
92 | alpha_v = alpha_v,
93 | rank = k
94 | ),
95 | # Penalties
96 | list(
97 | Omega_u = check_omega(Omega_u, alpha_u, n),
98 | Omega_v = check_omega(Omega_v, alpha_v, p),
99 | prox_arg_list_u = add_default_prox_args(u_sparsity),
100 | prox_arg_list_v = add_default_prox_args(v_sparsity)
101 | ),
102 | pg_settings
103 | )
104 |
105 | if (is_multiple_para) {
106 | if (select == "gridsearch") {
107 | a <- do.call("cpp_moma_grid_search", algo_settings_list)
108 | class(a) <- "moma_svd_grid"
109 | return(a)
110 | }
111 | else if (select == "nestedBIC") {
112 | a <- do.call("cpp_moma_criterion_search", algo_settings_list)
113 | class(a) <- "moma_svd_nestedBIC"
114 | return(a)
115 | }
116 | else {
117 | moma_error("Wrong parameter selection methods!")
118 | }
119 | }
120 | else {
121 | return(do.call("cpp_moma_multi_rank", algo_settings_list))
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/R/moma_solve.R:
--------------------------------------------------------------------------------
1 | sfpca <- function(X,
2 | # sparsity
3 | P_v = "none",
4 | P_u = "none",
5 | lambda_v = 0, # a vector or scalar, same for lambda_u, alpha_u/v
6 | lambda_u = 0,
7 | gamma_v = 3,
8 | gamma_u = 3,
9 | # non-negativity
10 | nonneg_u = FALSE,
11 | nonneg_v = FALSE,
12 | # grouping
13 | group_u = MOMA_EMPTYVEC,
14 | group_v = MOMA_EMPTYVEC,
15 | # sparse fused lasso
16 | lambda2_u = 0, # penalty on the abs value of parameters
17 | lambda2_v = 0,
18 | # unordered fusion
19 | w_u = MOMA_EMPTYMAT,
20 | w_v = MOMA_EMPTYMAT,
21 | ADMM_u = FALSE,
22 | ADMM_v = FALSE,
23 | acc_u = FALSE,
24 | acc_v = FALSE,
25 | prox_eps_u = 1e-10,
26 | prox_eps_v = 1e-10,
27 | # trend filtering
28 | l1tf_k_u = 1,
29 | l1tf_k_v = 1,
30 | # smoothness
31 | Omega_u = NULL,
32 | Omega_v = NULL,
33 | alpha_u = 0,
34 | alpha_v = 0,
35 | # algorithm parameters
36 | EPS = 1e-10,
37 | MAX_ITER = 1000,
38 | EPS_inner = 1e-10,
39 | MAX_ITER_inner = 1e+5,
40 | solver = "ista",
41 | k = 1) {
42 | if (!is.null(X) && !is.matrix(X)) {
43 | moma_error("X must be a matrix.")
44 | }
45 | n <- dim(X)[1]
46 | p <- dim(X)[2]
47 |
48 |
49 | P_u <- toupper(P_u)
50 | P_v <- toupper(P_v)
51 | solver <- toupper(solver)
52 |
53 | alpha_u <- as.vector(alpha_u)
54 | alpha_v <- as.vector(alpha_v)
55 | lambda_u <- as.vector(lambda_u)
56 | lambda_v <- as.vector(lambda_v)
57 |
58 | Omega_u <- Omega_u %||% diag(dim(X)[1])
59 | Omega_v <- Omega_v %||% diag(dim(X)[2])
60 |
61 | prox_arg_list_u <- list(
62 | w = w_u,
63 | Omega = Omega_u,
64 | alpha = alpha_u,
65 | lambda = lambda_u,
66 | P = P_u,
67 | gamma = gamma_u,
68 | lambda2 = lambda2_u,
69 | ADMM = ADMM_u,
70 | acc = acc_u,
71 | prox_eps = prox_eps_u,
72 | l1tf_k = l1tf_k_u,
73 | nonneg = nonneg_u,
74 | group = group_u
75 | )
76 | prox_arg_list_v <- list(
77 | w = w_v,
78 | Omega = Omega_v,
79 | alpha = alpha_v,
80 | lambda = lambda_v,
81 | P = P_v,
82 | gamma = gamma_v,
83 | lambda2 = lambda2_v,
84 | ADMM = ADMM_v,
85 | acc = acc_v,
86 | prox_eps = prox_eps_v,
87 | l1tf_k = l1tf_k_v,
88 | nonneg = nonneg_v,
89 | group = group_v
90 | )
91 | return(cpp_moma_multi_rank(
92 | X = X,
93 | alpha_u = alpha_u, alpha_v = alpha_v,
94 | Omega_u = Omega_u, Omega_v = Omega_v,
95 | lambda_u = lambda_u, lambda_v = lambda_v,
96 | prox_arg_list_u = prox_arg_list_u,
97 | prox_arg_list_v = prox_arg_list_v,
98 | EPS = EPS, MAX_ITER = MAX_ITER,
99 | EPS_inner = EPS_inner, MAX_ITER_inner = MAX_ITER_inner,
100 | solver = solver,
101 | rank = k
102 | ))
103 | }
104 |
--------------------------------------------------------------------------------
/R/zzz.R:
--------------------------------------------------------------------------------
1 | .onAttach <- function(...) { # nocov start
2 | if (interactive()) {
3 | msg <- c(
4 | "Thank you for using MoMA!",
5 | "The current logging level is",
6 | sQuote(paste0(moma_logger_level(), ".")),
7 | "To change this, see ?moma_logging."
8 | )
9 |
10 | packageStartupMessage(paste(msg, collapse = " "))
11 | }
12 | } # nocov end
13 |
--------------------------------------------------------------------------------
/_pkgdown.yml:
--------------------------------------------------------------------------------
1 | template:
2 | params:
3 | bootswatch: flatly
4 |
5 | navbar:
6 | type: inverse
7 | right:
8 | - icon: fa-github fa-lg
9 | href: https://github.com/DataSlingers/MoMA
10 | left:
11 | - text: Intro
12 | href: articles/moma-quick-start.html
13 | - text: Reference
14 | href: reference/index.html
15 | - text: Articles
16 | menu:
17 | - text: Funtional Data Analysis
18 | href: articles/moma-functional-data-analysis.html
19 | - text: Principal Component Anlaysis
20 | href: articles/moma-PCA.html
21 | - text: Linear Discriminant Analysis
22 | href: articles/moma-LDA.html
23 |
24 | reference:
25 | - title: Home Page
26 | desc: ~
27 | contents:
28 | - 'MoMA'
29 | - title: Sparsity Choices
30 | desc: ~
31 | contents:
32 | - 'moma_sparsity_options'
33 | - '`lasso`'
34 | - '`mcp`'
35 | - '`scad`'
36 | - '`fused_lasso`'
37 | - '`sparse_fused_lasso`'
38 | - '`slope`'
39 | - '`group_lasso`'
40 | - '`l1_trend_filtering`'
41 | - '`cluster`'
42 | - title: Smoothness Choices
43 | desc: ~
44 | contents:
45 | - '`moma_smoothness`'
46 | - '`second_diff_mat`'
47 | - title: Selection Scheme of Tuning Parameters
48 | desc: ~
49 | contents:
50 | - '`select_scheme`'
51 | - title: Deflation Schemes
52 | desc: ~
53 | contents:
54 | - '`PCA_deflation`'
55 | - '`CCA_deflation`'
56 | - '`LDA_deflation`'
57 | - title: Multivariate Models
58 | desc: ~
59 | contents:
60 | - '`moma_R6`'
61 | - '`moma_sfcca`'
62 | - '`moma_sflda`'
63 | - '`moma_sfpca`'
64 | - title: Logging
65 | desc: ~
66 | contents:
67 | - '`moma_logger_level`'
68 | - '`moma_session_info`'
69 | - title: Algorithm Settings
70 | desc: ~
71 | contents:
72 | - '`moma_pg_settings`'
73 |
--------------------------------------------------------------------------------
/docs/SUPPORT.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | NA • MoMA
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
66 |
67 |
68 |
94 |
95 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
116 |
117 |
118 |
Thank you for using MoMA
!
119 |
Feature requests can be reported on the issue tracker .
120 |
For help using the existing features of MoMA
, please contact Michael Weylandt and include the tag “[MoMA package help]” in your subject line. Please include the output of moma::moma_session_info()
in your email.
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/docs/articles/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Articles • MoMA
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
66 |
67 |
68 |
94 |
95 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
116 |
117 |
118 |
All vignettes
119 |
120 |
121 |
127 |
128 |
129 |
130 |
131 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-3-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-3-1.png
--------------------------------------------------------------------------------
/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-4-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-4-1.png
--------------------------------------------------------------------------------
/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-5-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-5-1.png
--------------------------------------------------------------------------------
/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-7-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/docs/articles/moma-functional-data-analysis_files/figure-html/unnamed-chunk-7-1.png
--------------------------------------------------------------------------------
/docs/authors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Authors • MoMA
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
66 |
67 |
68 |
94 |
95 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
116 |
117 |
118 |
119 | Michael Weylandt . Author, maintainer.
120 |
121 |
122 |
123 | Genevera Allen . Author.
124 |
125 |
126 |
127 | Luofeng Liao . Author.
128 |
129 |
130 |
131 | Nicholas Johnson . Copyright holder.
132 | src/moma_prox_flsadp.cpp
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/docs/docsearch.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // register a handler to move the focus to the search bar
4 | // upon pressing shift + "/" (i.e. "?")
5 | $(document).on('keydown', function(e) {
6 | if (e.shiftKey && e.keyCode == 191) {
7 | e.preventDefault();
8 | $("#search-input").focus();
9 | }
10 | });
11 |
12 | $(document).ready(function() {
13 | // do keyword highlighting
14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */
15 | var mark = function() {
16 |
17 | var referrer = document.URL ;
18 | var paramKey = "q" ;
19 |
20 | if (referrer.indexOf("?") !== -1) {
21 | var qs = referrer.substr(referrer.indexOf('?') + 1);
22 | var qs_noanchor = qs.split('#')[0];
23 | var qsa = qs_noanchor.split('&');
24 | var keyword = "";
25 |
26 | for (var i = 0; i < qsa.length; i++) {
27 | var currentParam = qsa[i].split('=');
28 |
29 | if (currentParam.length !== 2) {
30 | continue;
31 | }
32 |
33 | if (currentParam[0] == paramKey) {
34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20"));
35 | }
36 | }
37 |
38 | if (keyword !== "") {
39 | $(".contents").unmark({
40 | done: function() {
41 | $(".contents").mark(keyword);
42 | }
43 | });
44 | }
45 | }
46 | };
47 |
48 | mark();
49 | });
50 | });
51 |
52 | /* Search term highlighting ------------------------------*/
53 |
54 | function matchedWords(hit) {
55 | var words = [];
56 |
57 | var hierarchy = hit._highlightResult.hierarchy;
58 | // loop to fetch from lvl0, lvl1, etc.
59 | for (var idx in hierarchy) {
60 | words = words.concat(hierarchy[idx].matchedWords);
61 | }
62 |
63 | var content = hit._highlightResult.content;
64 | if (content) {
65 | words = words.concat(content.matchedWords);
66 | }
67 |
68 | // return unique words
69 | var words_uniq = [...new Set(words)];
70 | return words_uniq;
71 | }
72 |
73 | function updateHitURL(hit) {
74 |
75 | var words = matchedWords(hit);
76 | var url = "";
77 |
78 | if (hit.anchor) {
79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor;
80 | } else {
81 | url = hit.url + '?q=' + escape(words.join(" "));
82 | }
83 |
84 | return url;
85 | }
86 |
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/pkgdown.css:
--------------------------------------------------------------------------------
1 | /* Sticky footer */
2 |
3 | /**
4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css
6 | *
7 | * .Site -> body > .container
8 | * .Site-content -> body > .container .row
9 | * .footer -> footer
10 | *
11 | * Key idea seems to be to ensure that .container and __all its parents__
12 | * have height set to 100%
13 | *
14 | */
15 |
16 | html, body {
17 | height: 100%;
18 | }
19 |
20 | body > .container {
21 | display: flex;
22 | height: 100%;
23 | flex-direction: column;
24 |
25 | padding-top: 60px;
26 | }
27 |
28 | body > .container .row {
29 | flex: 1 0 auto;
30 | }
31 |
32 | footer {
33 | margin-top: 45px;
34 | padding: 35px 0 36px;
35 | border-top: 1px solid #e5e5e5;
36 | color: #666;
37 | display: flex;
38 | flex-shrink: 0;
39 | }
40 | footer p {
41 | margin-bottom: 0;
42 | }
43 | footer div {
44 | flex: 1;
45 | }
46 | footer .pkgdown {
47 | text-align: right;
48 | }
49 | footer p {
50 | margin-bottom: 0;
51 | }
52 |
53 | img.icon {
54 | float: right;
55 | }
56 |
57 | img {
58 | max-width: 100%;
59 | }
60 |
61 | /* Fix bug in bootstrap (only seen in firefox) */
62 | summary {
63 | display: list-item;
64 | }
65 |
66 | /* Typographic tweaking ---------------------------------*/
67 |
68 | .contents .page-header {
69 | margin-top: calc(-60px + 1em);
70 | }
71 |
72 | /* Section anchors ---------------------------------*/
73 |
74 | a.anchor {
75 | margin-left: -30px;
76 | display:inline-block;
77 | width: 30px;
78 | height: 30px;
79 | visibility: hidden;
80 |
81 | background-image: url(./link.svg);
82 | background-repeat: no-repeat;
83 | background-size: 20px 20px;
84 | background-position: center center;
85 | }
86 |
87 | .hasAnchor:hover a.anchor {
88 | visibility: visible;
89 | }
90 |
91 | @media (max-width: 767px) {
92 | .hasAnchor:hover a.anchor {
93 | visibility: hidden;
94 | }
95 | }
96 |
97 |
98 | /* Fixes for fixed navbar --------------------------*/
99 |
100 | .contents h1, .contents h2, .contents h3, .contents h4 {
101 | padding-top: 60px;
102 | margin-top: -40px;
103 | }
104 |
105 | /* Static header placement on mobile devices */
106 | @media (max-width: 767px) {
107 | .navbar-fixed-top {
108 | position: absolute;
109 | }
110 | .navbar {
111 | padding: 0;
112 | }
113 | }
114 |
115 |
116 | /* Sidebar --------------------------*/
117 |
118 | #sidebar {
119 | margin-top: 30px;
120 | }
121 | #sidebar h2 {
122 | font-size: 1.5em;
123 | margin-top: 1em;
124 | }
125 |
126 | #sidebar h2:first-child {
127 | margin-top: 0;
128 | }
129 |
130 | #sidebar .list-unstyled li {
131 | margin-bottom: 0.5em;
132 | }
133 |
134 | .orcid {
135 | height: 16px;
136 | vertical-align: middle;
137 | }
138 |
139 | /* Reference index & topics ----------------------------------------------- */
140 |
141 | .ref-index th {font-weight: normal;}
142 |
143 | .ref-index td {vertical-align: top;}
144 | .ref-index .icon {width: 40px;}
145 | .ref-index .alias {width: 40%;}
146 | .ref-index-icons .alias {width: calc(40% - 40px);}
147 | .ref-index .title {width: 60%;}
148 |
149 | .ref-arguments th {text-align: right; padding-right: 10px;}
150 | .ref-arguments th, .ref-arguments td {vertical-align: top;}
151 | .ref-arguments .name {width: 20%;}
152 | .ref-arguments .desc {width: 80%;}
153 |
154 | /* Nice scrolling for wide elements --------------------------------------- */
155 |
156 | table {
157 | display: block;
158 | overflow: auto;
159 | }
160 |
161 | /* Syntax highlighting ---------------------------------------------------- */
162 |
163 | pre {
164 | word-wrap: normal;
165 | word-break: normal;
166 | border: 1px solid #eee;
167 | }
168 |
169 | pre, code {
170 | background-color: #f8f8f8;
171 | color: #333;
172 | }
173 |
174 | pre code {
175 | overflow: auto;
176 | word-wrap: normal;
177 | white-space: pre;
178 | }
179 |
180 | pre .img {
181 | margin: 5px 0;
182 | }
183 |
184 | pre .img img {
185 | background-color: #fff;
186 | display: block;
187 | height: auto;
188 | }
189 |
190 | code a, pre a {
191 | color: #375f84;
192 | }
193 |
194 | a.sourceLine:hover {
195 | text-decoration: none;
196 | }
197 |
198 | .fl {color: #1514b5;}
199 | .fu {color: #000000;} /* function */
200 | .ch,.st {color: #036a07;} /* string */
201 | .kw {color: #264D66;} /* keyword */
202 | .co {color: #888888;} /* comment */
203 |
204 | .message { color: black; font-weight: bolder;}
205 | .error { color: orange; font-weight: bolder;}
206 | .warning { color: #6A0366; font-weight: bolder;}
207 |
208 | /* Clipboard --------------------------*/
209 |
210 | .hasCopyButton {
211 | position: relative;
212 | }
213 |
214 | .btn-copy-ex {
215 | position: absolute;
216 | right: 0;
217 | top: 0;
218 | visibility: hidden;
219 | }
220 |
221 | .hasCopyButton:hover button.btn-copy-ex {
222 | visibility: visible;
223 | }
224 |
225 | /* mark.js ----------------------------*/
226 |
227 | mark {
228 | background-color: rgba(255, 255, 51, 0.5);
229 | border-bottom: 2px solid rgba(255, 153, 51, 0.3);
230 | padding: 1px;
231 | }
232 |
233 | /* vertical spacing after htmlwidgets */
234 | .html-widget {
235 | margin-bottom: 10px;
236 | }
237 |
--------------------------------------------------------------------------------
/docs/pkgdown.js:
--------------------------------------------------------------------------------
1 | /* http://gregfranko.com/blog/jquery-best-practices/ */
2 | (function($) {
3 | $(function() {
4 |
5 | $("#sidebar")
6 | .stick_in_parent({offset_top: 40})
7 | .on('sticky_kit:bottom', function(e) {
8 | $(this).parent().css('position', 'static');
9 | })
10 | .on('sticky_kit:unbottom', function(e) {
11 | $(this).parent().css('position', 'relative');
12 | });
13 |
14 | $('body').scrollspy({
15 | target: '#sidebar',
16 | offset: 60
17 | });
18 |
19 | $('[data-toggle="tooltip"]').tooltip();
20 |
21 | var cur_path = paths(location.pathname);
22 | var links = $("#navbar ul li a");
23 | var max_length = -1;
24 | var pos = -1;
25 | for (var i = 0; i < links.length; i++) {
26 | if (links[i].getAttribute("href") === "#")
27 | continue;
28 | // Ignore external links
29 | if (links[i].host !== location.host)
30 | continue;
31 |
32 | var nav_path = paths(links[i].pathname);
33 |
34 | var length = prefix_length(nav_path, cur_path);
35 | if (length > max_length) {
36 | max_length = length;
37 | pos = i;
38 | }
39 | }
40 |
41 | // Add class to parent , and enclosing if in dropdown
42 | if (pos >= 0) {
43 | var menu_anchor = $(links[pos]);
44 | menu_anchor.parent().addClass("active");
45 | menu_anchor.closest("li.dropdown").addClass("active");
46 | }
47 | });
48 |
49 | function paths(pathname) {
50 | var pieces = pathname.split("/");
51 | pieces.shift(); // always starts with /
52 |
53 | var end = pieces[pieces.length - 1];
54 | if (end === "index.html" || end === "")
55 | pieces.pop();
56 | return(pieces);
57 | }
58 |
59 | // Returns -1 if not found
60 | function prefix_length(needle, haystack) {
61 | if (needle.length > haystack.length)
62 | return(-1);
63 |
64 | // Special case for length-0 haystack, since for loop won't run
65 | if (haystack.length === 0) {
66 | return(needle.length === 0 ? 0 : -1);
67 | }
68 |
69 | for (var i = 0; i < haystack.length; i++) {
70 | if (needle[i] != haystack[i])
71 | return(i);
72 | }
73 |
74 | return(haystack.length);
75 | }
76 |
77 | /* Clipboard --------------------------*/
78 |
79 | function changeTooltipMessage(element, msg) {
80 | var tooltipOriginalTitle=element.getAttribute('data-original-title');
81 | element.setAttribute('data-original-title', msg);
82 | $(element).tooltip('show');
83 | element.setAttribute('data-original-title', tooltipOriginalTitle);
84 | }
85 |
86 | if(ClipboardJS.isSupported()) {
87 | $(document).ready(function() {
88 | var copyButton = " ";
89 |
90 | $(".examples, div.sourceCode").addClass("hasCopyButton");
91 |
92 | // Insert copy buttons:
93 | $(copyButton).prependTo(".hasCopyButton");
94 |
95 | // Initialize tooltips:
96 | $('.btn-copy-ex').tooltip({container: 'body'});
97 |
98 | // Initialize clipboard:
99 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', {
100 | text: function(trigger) {
101 | return trigger.parentNode.textContent;
102 | }
103 | });
104 |
105 | clipboardBtnCopies.on('success', function(e) {
106 | changeTooltipMessage(e.trigger, 'Copied!');
107 | e.clearSelection();
108 | });
109 |
110 | clipboardBtnCopies.on('error', function() {
111 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy');
112 | });
113 | });
114 | }
115 | })(window.jQuery || window.$)
116 |
--------------------------------------------------------------------------------
/docs/pkgdown.yml:
--------------------------------------------------------------------------------
1 | pandoc: '2.2'
2 | pkgdown: 1.3.0
3 | pkgdown_sha: ~
4 | articles:
5 | moma-LDA: moma-LDA.html
6 | moma-PCA: moma-PCA.html
7 | moma-functional-data-analysis: moma-functional-data-analysis.html
8 | moma-quick-start: moma-quick-start.html
9 |
10 |
--------------------------------------------------------------------------------
/docs/reference/MoMA.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MoMA: Modern Multivariate Analysis in R — MoMA • MoMA
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
69 |
70 |
71 |
97 |
98 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
121 |
122 |
123 |
124 |
TODO
125 |
126 |
127 |
128 |
129 |
Details
130 |
131 |
See the package vignettes for details of the algorithm, as well as
132 | comparisons to existing methods.
133 |
134 |
135 |
136 |
144 |
145 |
146 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/docs/reference/figures/README-usage-ldademo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/docs/reference/figures/README-usage-ldademo.png
--------------------------------------------------------------------------------
/docs/reference/figures/vignettes-pca-demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/docs/reference/figures/vignettes-pca-demo.png
--------------------------------------------------------------------------------
/docs/reference/moma_session_info.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Session Info used for Bug Reporting — moma_session_info • MoMA
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
70 |
71 |
72 |
98 |
99 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
122 |
123 |
124 |
125 |
A helper function which prints information useful in
126 | bug reports.
127 |
128 |
129 |
130 |
moma_session_info ()
131 |
132 |
Value
133 |
134 |
None. Called for side-effects (printed to the screen)
135 | only.
136 |
137 |
138 |
139 |
147 |
148 |
149 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/inst/GIT.HASH:
--------------------------------------------------------------------------------
1 | 92842d1720b5f96d119a81a7eb2c5afb7e00f722
2 |
--------------------------------------------------------------------------------
/man/CCA_deflation.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_sfcca.R
3 | \name{CCA_deflation}
4 | \alias{CCA_deflation}
5 | \title{The Deflation Scheme for CCA}
6 | \description{
7 | In \code{MoMA} one deflation scheme is provided for CCA.
8 | }
9 | \details{
10 | Let \eqn{X,Y} be two data matrices (properly scaled and centered) of the same number of
11 | rows. Each row represents a sample. The penalized CCA problem is formulated as
12 |
13 | \eqn{ \min_{u,v} \, u^T X^T Y v + \lambda_u P_u(u) + \lambda_v P_v(v) }
14 |
15 | \eqn{ \text{s.t. } \| u \|_{I+\alpha_u \Omega_u} \leq 1, \| v \|_{I + \alpha_v \Omega_v} \leq 1. }
16 |
17 | In the discussion below, let \eqn{u,v} be the solution to the above problem.
18 | Let \eqn{c_x = Xu, c_y = Yv}. The deflation scheme is as follow:
19 |
20 | \eqn{X \leftarrow { X } - { c_x } \left( { c_x } ^ { T } { c_x } \right) ^ { - 1 } { c_x } ^ { T } { X }
21 | = ( I - { c_x } \left( { c_x } ^ { T } { c_x } \right) ^ { - 1 } { c_x } ^ { T } )X,}
22 |
23 | \eqn{ Y \leftarrow { Y } - { c_y } \left( { c_y } ^ { T } { c_y } \right) ^ { - 1 } { c_y } ^ { T } { Y }
24 | = (I - { c_y } \left( { c_y } ^ { T } { c_y } \right) ^ { - 1 } { c_y } ^ { T } ) Y}.
25 | }
26 | \references{
27 | De Bie T., Cristianini N., Rosipal R. (2005) Eigenproblems
28 | in Pattern Recognition. In: Handbook of Geometric Computing. Springer, Berlin, Heidelberg
29 | }
30 |
--------------------------------------------------------------------------------
/man/LDA_deflation.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_sflda.R
3 | \name{LDA_deflation}
4 | \alias{LDA_deflation}
5 | \title{The Deflation Scheme for LDA}
6 | \description{
7 | In \code{MoMA} one deflation scheme is provided for LDA.
8 | }
9 | \details{
10 | Let \eqn{X} be a data matrix (properly scaled and centered), and \eqn{Y}
11 | be the indicator matrix showing which group a sample belongs to.
12 | \eqn{X} and \eqn{Y} should have the same number of columns. The penalized LDA problem is formulated as
13 |
14 | \eqn{ \min_{u,v} \, u^T X^T Y v + \lambda_u P_u(u) + \lambda_v P_v(v) }
15 |
16 | \eqn{ \text{s.t. } \| u \|_{I+\alpha_u \Omega_u} \leq 1, \| v \|_{I + \alpha_v \Omega_v} \leq 1. }
17 |
18 | In the discussion below, let \eqn{u,v} be the solution to the above problem.
19 | Let \eqn{c_x = Xu, c_y = Yv}. The deflation scheme is as follow:
20 |
21 | \eqn{X \leftarrow { X } - { c_x } \left( { c_x } ^ { T } { c_x } \right) ^ { - 1 } { c_x } ^ { T } { X }
22 | = ( I - { c_x } \left( { c_x } ^ { T } { c_x } \right) ^ { - 1 } { c_x } ^ { T } )X,}
23 |
24 | \eqn{ Y \text{ remains unchanged.}}.
25 | }
26 | \references{
27 | De Bie T., Cristianini N., Rosipal R. (2005) Eigenproblems
28 | in Pattern Recognition. In: Handbook of Geometric Computing. Springer, Berlin, Heidelberg
29 | }
30 |
--------------------------------------------------------------------------------
/man/MoMA.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma-package.R
3 | \docType{package}
4 | \name{MoMA}
5 | \alias{MoMA}
6 | \alias{MoMA-package}
7 | \title{MoMA: Modern Multivariate Analysis in R}
8 | \description{
9 | TODO
10 | }
11 | \details{
12 | See the package vignettes for details of the algorithm, as well as
13 | comparisons to existing methods.
14 | }
15 |
--------------------------------------------------------------------------------
/man/PCA_deflation.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_sfpca.R
3 | \name{PCA_deflation}
4 | \alias{PCA_deflation}
5 | \title{Deflation Schemes for PCA}
6 | \description{
7 | In \code{MoMA} three deflation schemes are provided for PCA.
8 | Using terminology in the reference, they are Hotelling's deflation,
9 | two-way projection deflation, and Schur complement deflation.
10 | }
11 | \details{
12 | See the parameter \code{deflation_scheme} argument in the function
13 | \code{moma_sfpca}. Also refer to the reference below
14 | for theoretical properties.
15 | }
16 | \references{
17 | Michael Weylandt. "Multi-Rank Sparse and Functional PCA: Manifold Optimization and
18 | Iterative Deflation Techniques." arXiv:1907.12012v1, 2019.
19 | }
20 |
--------------------------------------------------------------------------------
/man/cluster.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{cluster}
4 | \alias{cluster}
5 | \alias{moma_cluster}
6 | \title{Cluster penalty}
7 | \usage{
8 | moma_cluster(..., w = NULL, ADMM = FALSE, acc = FALSE, eps = 1e-10,
9 | ..., lambda = 0, select_scheme = "g")
10 | }
11 | \arguments{
12 | \item{...}{Forces users to specify all arguments by name.}
13 |
14 | \item{w}{A symmetric square matrix. \code{w[i, j]} is the \eqn{w_{ij}} described above.}
15 |
16 | \item{ADMM}{A Boolean value. Set to \code{TRUE} to use ADMM, set to \code{FALSE} to use AMA. Defaults to FALSE.}
17 |
18 | \item{acc}{A Boolean value. Set to \code{TRUE} to use the accelerated version of the algorithm.
19 | Currently we support accelerated AMA only.}
20 |
21 | \item{eps}{A small numeric value. The precision used when solving the proximal operator.}
22 |
23 | \item{lambda}{A vector containing penalty values}
24 |
25 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
26 |
27 | MoMA provides a flexible framework for regularized multivariate analysis
28 | with several tuning parameters for different forms of regularization.
29 | To assist the user in selecting these parameters (\code{alpha_u},
30 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
31 | two selection modes: grid search ("g") and nested BIC search ("b").
32 | Grid search means we solve the problem
33 | for all combinations of parameter values provided by the user.
34 |
35 | To explain nested BIC search, we need to look into how the algorithm runs.
36 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
37 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
38 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
39 | For each regression problem, we can select the optimal parameters
40 | based on BIC.
41 |
42 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
43 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
44 | current estimate of \emph{u}, and then do the same thing for problem v,
45 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
46 | the above until convergence or the maximal number of iterations has been reached.
47 |
48 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
49 | in the paper cited below.}
50 | }
51 | \value{
52 | A \code{moma_sparsity_type} object, which is a list containing the values of \code{w},
53 | \code{ADMM}, \code{acc} and \code{eps}.
54 | }
55 | \description{
56 | Use this function to set the penalty function to
57 | \deqn{\lambda \sum w_{ij} | x_{i} - x_{j} |,}
58 | where \eqn{\lambda} is set by the \code{lambda} argument below.
59 | }
60 | \references{
61 | Chi, Eric C., and Kenneth Lange. "Splitting Methods for Convex Clustering."
62 | Journal of Computational and Graphical Statistics 24.4 (2015): 994-1013. \doi{10.1080/10618600.2014.948181}.
63 | }
64 |
--------------------------------------------------------------------------------
/man/figures/README-usage-ldademo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/man/figures/README-usage-ldademo.png
--------------------------------------------------------------------------------
/man/figures/vignettes-pca-demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DataSlingers/MoMA/b3a0085265990916da033d7acf494b676384229e/man/figures/vignettes-pca-demo.png
--------------------------------------------------------------------------------
/man/fused_lasso.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{fused_lasso}
4 | \alias{fused_lasso}
5 | \alias{moma_fusedlasso}
6 | \title{Fused LASSO}
7 | \usage{
8 | moma_fusedlasso(..., algo = c("path", "dp"), ..., lambda = 0,
9 | select_scheme = "g")
10 | }
11 | \arguments{
12 | \item{...}{Forces users to specify all arguments by name.}
13 |
14 | \item{algo}{A string being either "path" or "dp". Defaults to "path". Partial matching
15 | is supported. Two solving algorithms
16 | are provided. When "path" is chosen, the algorithm by
17 | Hoefling, H. (2010) is used. When "dp" is chosen, the algorithm by Johnson, N. A. (2013) is used.}
18 |
19 | \item{lambda}{A vector containing penalty values}
20 |
21 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
22 |
23 | MoMA provides a flexible framework for regularized multivariate analysis
24 | with several tuning parameters for different forms of regularization.
25 | To assist the user in selecting these parameters (\code{alpha_u},
26 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
27 | two selection modes: grid search ("g") and nested BIC search ("b").
28 | Grid search means we solve the problem
29 | for all combinations of parameter values provided by the user.
30 |
31 | To explain nested BIC search, we need to look into how the algorithm runs.
32 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
33 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
34 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
35 | For each regression problem, we can select the optimal parameters
36 | based on BIC.
37 |
38 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
39 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
40 | current estimate of \emph{u}, and then do the same thing for problem v,
41 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
42 | the above until convergence or the maximal number of iterations has been reached.
43 |
44 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
45 | in the paper cited below.}
46 | }
47 | \value{
48 | A \code{moma_sparsity_type} object, which is an empty list.
49 | }
50 | \description{
51 | Use this function to set the penalty function to fused lasso
52 | \deqn{\lambda \sum | x_{i} - x_{i-1} |,}
53 | where \eqn{\lambda} is set by the \code{lambda} argument below.
54 | }
55 | \references{
56 | Tibshirani, Robert, et al. "Sparsity and Smoothness via the Fused Lasso."
57 | Journal of the Royal Statistical Society: Series B (Statistical Methodology) 67.1 (2005): 91-108.
58 | \doi{10.1111/j.1467-9868.2005.00490.x}.
59 |
60 | Hoefling, H. (2010). A path algorithm
61 | for the fused lasso signal approximator. Journal of Computational and Graphical
62 | Statistics, 19(4), 984-1006. \doi{10.1198/jcgs.2010.09208}.
63 |
64 | Johnson, N. A. (2013). A dynamic programming algorithm for the
65 | fused lasso and l 0-segmentation. Journal of Computational and Graphical
66 | Statistics, 22(2), 246-260. \doi{10.1080/10618600.2012.681238}.
67 | }
68 |
--------------------------------------------------------------------------------
/man/group_lasso.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{group_lasso}
4 | \alias{group_lasso}
5 | \alias{moma_grplasso}
6 | \title{Group LASSO}
7 | \usage{
8 | moma_grplasso(..., g, non_negative = FALSE, ..., lambda = 0,
9 | select_scheme = "g")
10 | }
11 | \arguments{
12 | \item{...}{Forces users to specify all arguments by name.}
13 |
14 | \item{g}{A vector of integer or characters, or a factor itself. It gets transformed
15 | to factor eventually to indicate grouping.}
16 |
17 | \item{non_negative}{A Boolean value. Set it to \code{TRUE} to add non-negativity
18 | constraint.}
19 |
20 | \item{lambda}{A vector containing penalty values}
21 |
22 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
23 |
24 | MoMA provides a flexible framework for regularized multivariate analysis
25 | with several tuning parameters for different forms of regularization.
26 | To assist the user in selecting these parameters (\code{alpha_u},
27 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
28 | two selection modes: grid search ("g") and nested BIC search ("b").
29 | Grid search means we solve the problem
30 | for all combinations of parameter values provided by the user.
31 |
32 | To explain nested BIC search, we need to look into how the algorithm runs.
33 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
34 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
35 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
36 | For each regression problem, we can select the optimal parameters
37 | based on BIC.
38 |
39 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
40 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
41 | current estimate of \emph{u}, and then do the same thing for problem v,
42 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
43 | the above until convergence or the maximal number of iterations has been reached.
44 |
45 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
46 | in the paper cited below.}
47 | }
48 | \value{
49 | A \code{moma_sparsity_type} object, which is a list containing the values of \code{non_negative}
50 | and \code{g}.
51 | }
52 | \description{
53 | Use this function to set the penalty function to group lasso
54 | \deqn{\lambda \sum_{g \in Group} \| x_g \|_1,}
55 | where \eqn{\lambda} is set by the \code{lambda} argument below, \eqn{x_g} is
56 | the vector comprised of elements of \eqn{x} picked out by the indices set \eqn{g}.
57 | }
58 | \references{
59 | Yuan, Ming, and Yi Lin. "Model Selection and Estimation in Regression
60 | with Grouped Variables." Journal of the Royal Statistical Society:
61 | Series B (Statistical Methodology) 68.1 (2006): 49-67. \doi{10.1111/j.1467-9868.2005.00532.x}.
62 | }
63 |
--------------------------------------------------------------------------------
/man/l1_trend_filtering.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{l1_trend_filtering}
4 | \alias{l1_trend_filtering}
5 | \alias{moma_l1tf}
6 | \title{L1 trend filtering}
7 | \usage{
8 | moma_l1tf(..., l1tf_k = 1, ..., lambda = 0, select_scheme = "g")
9 | }
10 | \arguments{
11 | \item{...}{Forces users to specify all arguments by name.}
12 |
13 | \item{l1tf_k}{Use (\eqn{k+1})-difference matrix in trend filtering. Note \eqn{k = 0}
14 | implies piecewise constant, \eqn{k=1} implies piecewise linear, \eqn{k=2}
15 | piecewise quadratic etc.}
16 |
17 | \item{lambda}{A vector containing penalty values}
18 |
19 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
20 |
21 | MoMA provides a flexible framework for regularized multivariate analysis
22 | with several tuning parameters for different forms of regularization.
23 | To assist the user in selecting these parameters (\code{alpha_u},
24 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
25 | two selection modes: grid search ("g") and nested BIC search ("b").
26 | Grid search means we solve the problem
27 | for all combinations of parameter values provided by the user.
28 |
29 | To explain nested BIC search, we need to look into how the algorithm runs.
30 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
31 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
32 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
33 | For each regression problem, we can select the optimal parameters
34 | based on BIC.
35 |
36 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
37 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
38 | current estimate of \emph{u}, and then do the same thing for problem v,
39 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
40 | the above until convergence or the maximal number of iterations has been reached.
41 |
42 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
43 | in the paper cited below.}
44 | }
45 | \value{
46 | A \code{moma_sparsity_type} object, which is an empty list.
47 | }
48 | \description{
49 | Use this function to set the penalty function to l1 trend filtering. An
50 | important special case is when \eqn{k=1}. In this case the penalty
51 | term becomes
52 | \deqn{\lambda \sum | x_{i-1} - 2x_{i} + x_{i+1} |,}
53 | where \eqn{\lambda} is set by the \code{lambda} argument below.
54 | }
55 | \details{
56 | The general formula of the penalty term for \eqn{k \in N} can be found in
57 | the paper cited in Reference. For other values of \eqn{k} please refer to the following table:
58 | \tabular{llll}{
59 | \tab \eqn{k = 0} \tab \eqn{k = 1} \tab \eqn{k = 2}
60 | \cr
61 | Type of sparsity \tab piecewise constant \tab peicewise linear \tab piecewise quadratic
62 | }
63 | }
64 | \references{
65 | Tibshirani, Ryan J. "Adaptive Piecewise Polynomial Estimation via Trend
66 | Filtering." The Annals of Statistics 42.1 (2014): 285-323. \doi{10.1214/13-AOS1189}.
67 |
68 | Aaditya Ramdas & Ryan J. Tibshirani (2016) Fast and Flexible ADMM
69 | Algorithms for Trend Filtering, Journal of Computational and Graphical Statistics,
70 | 25:3, 839-858. \doi{10.1080/10618600.2015.1054033}.
71 | }
72 |
--------------------------------------------------------------------------------
/man/lasso.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{lasso}
4 | \alias{lasso}
5 | \alias{moma_lasso}
6 | \title{LASSO (least absolute shrinkage and selection operator)}
7 | \usage{
8 | moma_lasso(..., non_negative = FALSE, ..., lambda = 0,
9 | select_scheme = "g")
10 | }
11 | \arguments{
12 | \item{...}{Forces users to specify all arguments by name.}
13 |
14 | \item{non_negative}{A Boolean value. Set \code{TRUE} to add non-negativity
15 | constraint.}
16 |
17 | \item{lambda}{A vector containing penalty values}
18 |
19 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
20 |
21 | MoMA provides a flexible framework for regularized multivariate analysis
22 | with several tuning parameters for different forms of regularization.
23 | To assist the user in selecting these parameters (\code{alpha_u},
24 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
25 | two selection modes: grid search ("g") and nested BIC search ("b").
26 | Grid search means we solve the problem
27 | for all combinations of parameter values provided by the user.
28 |
29 | To explain nested BIC search, we need to look into how the algorithm runs.
30 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
31 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
32 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
33 | For each regression problem, we can select the optimal parameters
34 | based on BIC.
35 |
36 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
37 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
38 | current estimate of \emph{u}, and then do the same thing for problem v,
39 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
40 | the above until convergence or the maximal number of iterations has been reached.
41 |
42 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
43 | in the paper cited below.}
44 | }
45 | \value{
46 | A \code{moma_sparsity_type} object, which is a list containing the value of \code{non_negative}
47 | }
48 | \description{
49 | Use this function to set the penalty function to LASSO
50 | \deqn{\lambda \sum | x_{i} | = \lambda \| x \|_1 ,}
51 | where \eqn{\lambda} is set by the \code{lambda} argument below.
52 | }
53 | \references{
54 | Tibshirani, Robert. "Regression Shrinkage and Selection via the Lasso."
55 | Journal of the Royal Statistical Society: Series B (Methodological) 58.1 (1996): 267-288. \doi{10.1111/j.2517-6161.1996.tb02080.x}.
56 | }
57 |
--------------------------------------------------------------------------------
/man/mcp.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{mcp}
4 | \alias{mcp}
5 | \alias{moma_mcp}
6 | \title{MCP (minimax concave penalty)}
7 | \usage{
8 | moma_mcp(..., gamma = 3, non_negative = FALSE, ..., lambda = 0,
9 | select_scheme = "g")
10 | }
11 | \arguments{
12 | \item{...}{Forces users to specify all arguments by name.}
13 |
14 | \item{gamma}{Non-convexity. Must be larger than 1.}
15 |
16 | \item{non_negative}{A Boolean value. Set to \code{TRUE} to add non-negativity
17 | constraint.}
18 |
19 | \item{lambda}{A vector containing penalty values}
20 |
21 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
22 |
23 | MoMA provides a flexible framework for regularized multivariate analysis
24 | with several tuning parameters for different forms of regularization.
25 | To assist the user in selecting these parameters (\code{alpha_u},
26 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
27 | two selection modes: grid search ("g") and nested BIC search ("b").
28 | Grid search means we solve the problem
29 | for all combinations of parameter values provided by the user.
30 |
31 | To explain nested BIC search, we need to look into how the algorithm runs.
32 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
33 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
34 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
35 | For each regression problem, we can select the optimal parameters
36 | based on BIC.
37 |
38 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
39 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
40 | current estimate of \emph{u}, and then do the same thing for problem v,
41 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
42 | the above until convergence or the maximal number of iterations has been reached.
43 |
44 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
45 | in the paper cited below.}
46 | }
47 | \value{
48 | A \code{moma_sparsity_type} object, which is a list containing the value of \code{non_negative}
49 | and \code{gamma}.
50 | }
51 | \description{
52 | Use this function to set the penalty function to MCP
53 | \deqn{ P (x; \lambda, \gamma) =
54 | \left\{\begin{array}{ll}{\lambda|x|-\frac{x^{2}}{2 \gamma},} & {
55 | \text { if }|x| \leq \gamma \lambda} \\ {\frac{1}{2} \gamma
56 | \lambda^{2},} & {\text { if }|x|>\gamma \lambda}\end{array}\right.,}
57 | where \eqn{\lambda} is set by the \code{lambda} argument below.
58 | }
59 | \references{
60 | Zhang, Cun-Hui. "Nearly Unbiased Variable
61 | Selection under Minimax Concave Penalty." The Annals of Statistics 38.2 (2010): 894-942. \doi{10.1214/09-AOS729}.
62 | }
63 |
--------------------------------------------------------------------------------
/man/moma_logging.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/logging.R
3 | \name{moma_logger_level}
4 | \alias{moma_logger_level}
5 | \alias{moma_logging}
6 | \title{MoMA Package Logging Functionality}
7 | \usage{
8 | moma_logger_level(level = c("ERROR", "WARNING", "MESSAGE", "INFO",
9 | "DEBUG"))
10 | }
11 | \arguments{
12 | \item{level}{The desired new log level. Available levels are \itemize{
13 | \item \code{ERROR} - corresponding to \code{base::stop};
14 | \item \code{WARNING} - corresponding to \code{base::warning};
15 | \item \code{MESSAGE} - corresponding to \code{base::message};
16 | \item \code{INFO}; and
17 | \item \code{DEBUG.}
18 | } If omitted, the log level is not changed (and the current level is still
19 | returned invisibly.) See below for details about the different levels.}
20 | }
21 | \value{
22 | The previous log level (invisibly).
23 | }
24 | \description{
25 | Control the global logging level for the \code{moma} package.
26 | }
27 | \details{
28 | The \code{moma} package has a multi-level logging system, with a single
29 | global log level; (which applies to both \code{R} and \code{C++} level
30 | functionality.) the levels are, in decreasing order, \code{ERROR},
31 | \code{WARNING}, \code{MESSAGE} (default), \code{INFO}, \code{DEBUG}.
32 |
33 | To change the amount of output from the \code{moma} package, the
34 | \code{moma_logger_level} function can be used to adjust the global
35 | log level. The \code{INFO} and \code{DEBUG} levels can be quite verbose
36 | and may significantly slow down the package.
37 | }
38 |
--------------------------------------------------------------------------------
/man/moma_pg_settings.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{moma_pg_settings}
4 | \alias{moma_pg_settings}
5 | \title{Algorithm settings for solving the penalized SVD problem}
6 | \usage{
7 | moma_pg_settings(..., EPS = 1e-10, MAX_ITER = 1000,
8 | EPS_inner = 1e-10, MAX_ITER_inner = 1e+05, solver = c("ista",
9 | "fista", "onestepista"))
10 | }
11 | \arguments{
12 | \item{...}{To force users to specify arguments by names.}
13 |
14 | \item{EPS}{Precision for outer loop.}
15 |
16 | \item{MAX_ITER}{The maximum number of iterations for outer loop.}
17 |
18 | \item{EPS_inner}{Precision for inner loop.}
19 |
20 | \item{MAX_ITER_inner}{The maximum number of iterations for inner loop.}
21 |
22 | \item{solver}{A string in \code{c("ista", "fista", "onestepista")}, representing ISTA (Iterative Shrinkage-Thresholding Algorithm),
23 | FISTA (Fast
24 | Iterative Shrinkage-Thresholding Algorithm) and One-step ISTA (an approximated
25 | version of ISTA) respectively.}
26 | }
27 | \value{
28 | A \code{moma_pg_settings} object, which is a list containing the above parameters.
29 | }
30 | \description{
31 | This function is used to specify the \code{pg_settings} argument
32 | in the \code{moma_*pca}, \code{moma_*cca}, and \code{moma_*lda}
33 | family of functions.
34 | }
35 | \details{
36 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
37 | penalized regression problems iteratively (outer loop). Each penalized regression (inner loop)
38 | is solved using one of the three algorithms: ISTA (Iterative Shrinkage-Thresholding Algorithm),
39 | FISTA (Fast Iterative Shrinkage-Thresholding Algorithm) and
40 | One-step ISTA (an approximated version of ISTA).
41 | }
42 |
--------------------------------------------------------------------------------
/man/moma_session_info.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/internals.R
3 | \name{moma_session_info}
4 | \alias{moma_session_info}
5 | \title{Session Info used for Bug Reporting}
6 | \usage{
7 | moma_session_info()
8 | }
9 | \value{
10 | None. Called for side-effects (printed to the screen)
11 | only.
12 | }
13 | \description{
14 | A helper function which prints information useful in
15 | bug reports.
16 | }
17 |
--------------------------------------------------------------------------------
/man/moma_sfcca.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_sfcca.R
3 | \name{moma_sfcca}
4 | \alias{moma_sfcca}
5 | \alias{moma_scca}
6 | \alias{moma_twscca}
7 | \alias{moma_fcca}
8 | \alias{moma_twfcca}
9 | \title{Sparse and functional CCA}
10 | \usage{
11 | moma_sfcca(X, ..., Y, center = TRUE, scale = FALSE,
12 | x_sparse = moma_empty(), y_sparse = moma_empty(),
13 | x_smooth = moma_smoothness(), y_smooth = moma_smoothness(),
14 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
15 |
16 | moma_scca(X, ..., Y, center = TRUE, scale = FALSE,
17 | x_sparse = moma_empty(), y_sparse = moma_empty(),
18 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
19 |
20 | moma_twscca(X, ..., Y, center = TRUE, scale = FALSE,
21 | x_sparse = moma_empty(), y_sparse = moma_empty(),
22 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
23 |
24 | moma_fcca(X, ..., Y, center = TRUE, scale = FALSE,
25 | x_smooth = moma_smoothness(), y_smooth = moma_smoothness(),
26 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
27 |
28 | moma_twfcca(X, ..., Y, center = TRUE, scale = FALSE,
29 | x_smooth = moma_smoothness(), y_smooth = moma_smoothness(),
30 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
31 | }
32 | \arguments{
33 | \item{X, Y}{A data matrix, each row representing a sample, and each column a feature.}
34 |
35 | \item{...}{Force users to specify arguments by names.}
36 |
37 | \item{center}{A logical value indicating whether the variables should be shifted to be zero centered.
38 | Defaults to \code{TRUE}.}
39 |
40 | \item{scale}{A logical value indicating whether the variables should be scaled to have unit variance.
41 | Defaults to \code{FALSE}.}
42 |
43 | \item{x_sparse, y_sparse}{An object of class inheriting from "\code{moma_sparsity_type}". Most conveniently
44 | specified by functions described in \code{\link{moma_sparsity_options}}. It specifies the type of sparsity-inducing
45 | penalty function used in the model. Note that for \code{moma_scca}, these two parameters must not be
46 | specified at the same time. For \code{moma_fcca} and \code{moma_twfcca}, they must not be specified.}
47 |
48 | \item{x_smooth, y_smooth}{An object of class inheriting from "\code{moma_smoothness_type}". Most conveniently
49 | specified by functions described in \code{moma_smoothness}. It specifies the type of smoothness
50 | terms used in the model. Note that for \code{moma_fcca}, these two parameters must not be
51 | specified at the same time. For \code{moma_scca} and \code{moma_twscca}, they must not be specified.}
52 |
53 | \item{pg_settings}{An object of class inheriting from "\code{moma_pg_settings}". Most conviently
54 | specified by functions described in \code{\link{moma_pg_settings}}. It specifies the type of algorithm
55 | used to solve the problem, acceptable level of precision, and the maximum number of iterations allowed.}
56 |
57 | \item{max_bic_iter}{A positive integer. Defaults to 5. The maximum number of iterations allowed
58 | in nested greedy BIC selection scheme.}
59 |
60 | \item{rank}{A positive integer. Defaults to 1. The maximal rank, i.e., maximal number of principal components to be used.}
61 | }
62 | \description{
63 | \code{moma_sfcca} creates an \code{SFCCA} R6 object and returns it. Type \code{?CCA_deflation} for
64 | description of problem formulation and deflation scheme.
65 |
66 | \code{moma_scca} is a function for performing one-way sparse CCA.
67 |
68 | \code{moma_twscca} is a function for performing two-way sparse CCA.
69 |
70 | \code{moma_fcca} is a function for performing one-way functional CCA.
71 |
72 | \code{moma_twfcca} is a function for performing two-way functional CCA.
73 | }
74 | \section{Functions}{
75 | \itemize{
76 | \item \code{moma_scca}: a function for performing one-way sparse CCA.
77 |
78 | \item \code{moma_twscca}: a function for performing two-way sparse CCA
79 |
80 | \item \code{moma_fcca}: a function for performing one-way functional CCA
81 |
82 | \item \code{moma_twfcca}: a function for performing two-way functional CCA
83 | }}
84 |
85 |
--------------------------------------------------------------------------------
/man/moma_sflda.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_sflda.R
3 | \name{moma_sflda}
4 | \alias{moma_sflda}
5 | \alias{moma_slda}
6 | \alias{moma_twslda}
7 | \alias{moma_flda}
8 | \alias{moma_twflda}
9 | \title{Sparse and functional LDA}
10 | \usage{
11 | moma_sflda(X, ..., Y_factor, center = TRUE, scale = FALSE,
12 | x_sparse = moma_empty(), y_sparse = moma_empty(),
13 | x_smooth = moma_smoothness(), y_smooth = moma_smoothness(),
14 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
15 |
16 | moma_slda(X, ..., Y_factor, center = TRUE, scale = FALSE,
17 | x_sparse = moma_empty(), y_sparse = moma_empty(),
18 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
19 |
20 | moma_twslda(X, ..., Y_factor, center = TRUE, scale = FALSE,
21 | x_sparse = moma_empty(), y_sparse = moma_empty(),
22 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
23 |
24 | moma_flda(X, ..., Y_factor, center = TRUE, scale = FALSE,
25 | x_smooth = moma_smoothness(), y_smooth = moma_smoothness(),
26 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
27 |
28 | moma_twflda(X, ..., Y_factor, center = TRUE, scale = FALSE,
29 | x_smooth = moma_smoothness(), y_smooth = moma_smoothness(),
30 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1)
31 | }
32 | \arguments{
33 | \item{X}{A data matrix, each row representing a sample, and each column a feature.}
34 |
35 | \item{...}{Force users to specify arguments by names.}
36 |
37 | \item{Y_factor}{A factor representing which group a sample belongs to.}
38 |
39 | \item{center}{A logical value indicating whether the variables should be shifted to be zero centered.
40 | Defaults to \code{TRUE}.}
41 |
42 | \item{scale}{A logical value indicating whether the variables should be scaled to have unit variance.
43 | Defaults to \code{FALSE}.}
44 |
45 | \item{x_sparse}{An object of class inheriting from "\code{moma_sparsity_type}". Most conveniently
46 | specified by functions described in \code{\link{moma_sparsity_options}}. It specifies the type of sparsity-inducing
47 | penalty function used in the model. Note that for \code{moma_scca}, these two parameters must not be
48 | specified at the same time. For \code{moma_fcca} and \code{moma_twfcca}, they must not be specified.}
49 |
50 | \item{y_sparse}{An object of class inheriting from "\code{moma_sparsity_type}". Most conveniently
51 | specified by functions described in \code{\link{moma_sparsity_options}}. It specifies the type of sparsity-inducing
52 | penalty function used in the model. Note that for \code{moma_scca}, these two parameters must not be
53 | specified at the same time. For \code{moma_fcca} and \code{moma_twfcca}, they must not be specified.}
54 |
55 | \item{x_smooth}{An object of class inheriting from "\code{moma_smoothness_type}". Most conveniently
56 | specified by functions described in \code{moma_smoothness}. It specifies the type of smoothness
57 | terms used in the model. Note that for \code{moma_fcca}, these two parameters must not be
58 | specified at the same time. For \code{moma_scca} and \code{moma_twscca}, they must not be specified.}
59 |
60 | \item{y_smooth}{An object of class inheriting from "\code{moma_smoothness_type}". Most conveniently
61 | specified by functions described in \code{moma_smoothness}. It specifies the type of smoothness
62 | terms used in the model. Note that for \code{moma_fcca}, these two parameters must not be
63 | specified at the same time. For \code{moma_scca} and \code{moma_twscca}, they must not be specified.}
64 |
65 | \item{pg_settings}{An object of class inheriting from "\code{moma_pg_settings}". Most conviently
66 | specified by functions described in \code{\link{moma_pg_settings}}. It specifies the type of algorithm
67 | used to solve the problem, acceptable level of precision, and the maximum number of iterations allowed.}
68 |
69 | \item{max_bic_iter}{A positive integer. Defaults to 5. The maximum number of iterations allowed
70 | in nested greedy BIC selection scheme.}
71 |
72 | \item{rank}{A positive integer. Defaults to 1. The maximal rank, i.e., maximal number of principal components to be used.}
73 | }
74 | \description{
75 | \code{moma_sflda} creates an \code{SFLDA} R6 object and returns it.
76 |
77 | \code{moma_slda} is a function for performing one-way sparse LDA.
78 |
79 | \code{moma_twslda} is a function for performing two-way sparse LDA.
80 |
81 | \code{moma_flda} is a function for performing one-way functional LDA.
82 |
83 | \code{moma_twflda} is a function for performing two-way functional LDA.
84 | }
85 | \section{Functions}{
86 | \itemize{
87 | \item \code{moma_slda}: a function for performing one-way sparse LDA
88 |
89 | \item \code{moma_twslda}: a function for performing two-way sparse LDA
90 |
91 | \item \code{moma_flda}: a function for performing one-way functional LDA
92 |
93 | \item \code{moma_twflda}: a function for performing two-way functional LDA
94 | }}
95 |
96 |
--------------------------------------------------------------------------------
/man/moma_sfpca.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_sfpca.R
3 | \name{moma_sfpca}
4 | \alias{moma_sfpca}
5 | \alias{moma_spca}
6 | \alias{moma_twspca}
7 | \alias{moma_fpca}
8 | \alias{moma_twfpca}
9 | \title{Sparse and functional PCA}
10 | \usage{
11 | moma_sfpca(X, ..., center = TRUE, scale = FALSE,
12 | u_sparse = moma_empty(), v_sparse = moma_lasso(),
13 | u_smooth = moma_smoothness(), v_smooth = moma_smoothness(),
14 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1,
15 | deflation_scheme = "PCA_Hotelling")
16 |
17 | moma_spca(X, ..., center = TRUE, scale = FALSE,
18 | u_sparse = moma_empty(), v_sparse = moma_lasso(),
19 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1,
20 | deflation_scheme = "PCA_Hotelling")
21 |
22 | moma_twspca(X, ..., center = TRUE, scale = FALSE,
23 | u_sparse = moma_lasso(), v_sparse = moma_lasso(),
24 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1,
25 | deflation_scheme = "PCA_Hotelling")
26 |
27 | moma_fpca(X, ..., center = TRUE, scale = FALSE,
28 | u_smooth = moma_smoothness(), v_smooth = moma_smoothness(),
29 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1,
30 | deflation_scheme = "PCA_Hotelling")
31 |
32 | moma_twfpca(X, ..., center = TRUE, scale = FALSE,
33 | u_smooth = moma_smoothness(), v_smooth = moma_smoothness(),
34 | pg_settings = moma_pg_settings(), max_bic_iter = 5, rank = 1,
35 | deflation_scheme = "PCA_Hotelling")
36 | }
37 | \arguments{
38 | \item{X}{A data matrix, each row representing a sample, and each column a feature.}
39 |
40 | \item{...}{Force users to specify arguments by names.}
41 |
42 | \item{center}{A logical value indicating whether the variables should be shifted to be zero centered.
43 | Defaults to \code{TRUE}.}
44 |
45 | \item{scale}{A logical value indicating whether the variables should be scaled to have unit variance.
46 | Defaults to \code{FALSE}.}
47 |
48 | \item{u_sparse, v_sparse}{An object of class inheriting from "\code{moma_sparsity_type}". Most conveniently
49 | specified by functions described in \code{\link{moma_sparsity_options}}. It specifies the type of sparsity-inducing
50 | penalty function used in the model. Note that for \code{moma_spca}, these two parameters must not be
51 | specified at the same time. For \code{moma_fpca} and \code{moma_twfpca}, they must not be specified.}
52 |
53 | \item{u_smooth, v_smooth}{An object of class inheriting from "\code{moma_smoothness_type}". Most conveniently
54 | specified by functions described in \code{moma_smoothness}. It specifies the type of smoothness
55 | terms used in the model. Note that for \code{moma_fpca}, these two parameters must not be
56 | specified at the same time. For \code{moma_spca} and \code{moma_twspca}, they must not be specified.}
57 |
58 | \item{pg_settings}{An object of class inheriting from "\code{moma_pg_settings}". Most conviently
59 | specified by functions described in \code{\link{moma_pg_settings}}. It specifies the type of algorithm
60 | used to solve the problem, acceptable level of precision, and the maximum number of iterations allowed.}
61 |
62 | \item{max_bic_iter}{A positive integer. Defaults to 5. The maximum number of iterations allowed
63 | in nested greedy BIC selection scheme.}
64 |
65 | \item{rank}{A positive integer. Defaults to 1. The maximal rank, i.e., maximal number of principal components to be used.}
66 |
67 | \item{deflation_scheme}{A string specifying the deflation scheme.
68 | It should be one of \code{"PCA_Hotelling", "PCA_Schur_Complement", "PCA_Projection"}.
69 |
70 | In the discussion below, let \eqn{u,v} be the normalized vectors obtained by
71 | scaling the penalized singular vectors.
72 |
73 | When \code{deflation_scheme = "Hotelling_deflation"} is specified, the following deflation
74 | scheme is used. \eqn{\boldsymbol{X}_{t} :=\boldsymbol{X}_{t-1}-d_{t} \boldsymbol{u}_{t} \boldsymbol{v}_{t}^{T}},
75 | where \eqn{d_{t}=\boldsymbol{u}_{t}^{T} \boldsymbol{X}_{t-1} \boldsymbol{v}_{t}}.
76 |
77 | When \code{deflation_scheme = "PCA_Schur_Complement"} is specified, the following deflation
78 | scheme is used: \eqn{\boldsymbol{X}_{t} :=\left(\boldsymbol{I}_{n}-
79 | \boldsymbol{u}_{t} \boldsymbol{u}_{t}^{T}\right) \boldsymbol{X}_{t-1}
80 | \left(\boldsymbol{I}_{p}-\boldsymbol{v}_{t} \boldsymbol{v}_{t}^{T}\right)}.
81 |
82 | When \code{deflation_scheme = "PCA_Projection"} is specified, the following deflation
83 | scheme is used:
84 | \eqn{\boldsymbol{X}_{t} :=\boldsymbol{X}_{t-1}-\frac{\boldsymbol{X}_{t-1}
85 | \boldsymbol{v}_{t} \boldsymbol{u}_{t}^{T} \boldsymbol{X}_{t-1}}{\boldsymbol{u}_{t}^{T}
86 | \boldsymbol{X}_{t-1} \boldsymbol{v}_{t}}}.}
87 | }
88 | \value{
89 | An R6 object which provides helper functions to access the results. See \code{\link{moma_R6}}.
90 | }
91 | \description{
92 | \code{moma_sfpca} creates an \code{SFPCA} R6 object and returns it.
93 |
94 | \code{moma_spca} is a function for performing one-way sparse PCA.
95 |
96 | \code{moma_twspca} is a function for performing two-way sparse PCA.
97 |
98 | \code{moma_fpca} is a function for performing one-way functional PCA.
99 |
100 | \code{moma_twfpca} is a function for performing two-way functional PCA.
101 | }
102 | \section{Functions}{
103 | \itemize{
104 | \item \code{moma_spca}: a function for performing one-way sparse PCA
105 |
106 | \item \code{moma_twspca}: a function for performing two-way sparse PCA
107 |
108 | \item \code{moma_fpca}: a function for performing one-way functional PCA
109 |
110 | \item \code{moma_twfpca}: a function for performing two-way functional PCA
111 | }}
112 |
113 |
--------------------------------------------------------------------------------
/man/moma_smoothness.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{moma_smoothness}
4 | \alias{moma_smoothness}
5 | \title{Smoothness-inducing Term}
6 | \usage{
7 | moma_smoothness(Omega = NULL, ..., alpha = 0, select_scheme = "g")
8 | }
9 | \arguments{
10 | \item{Omega}{A matrix of appropriate size. A common choice is the second difference matrix.
11 | See \code{\link{second_diff_mat}}.}
12 |
13 | \item{...}{Force users to specify arguments by names.}
14 |
15 | \item{alpha}{A vector containing penalty values}
16 |
17 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
18 |
19 | MoMA provides a flexible framework for regularized multivariate analysis
20 | with several tuning parameters for different forms of regularization.
21 | To assist the user in selecting these parameters (\code{alpha_u},
22 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
23 | two selection modes: grid search ("g") and nested BIC search ("b").
24 | Grid search means we solve the problem
25 | for all combinations of parameter values provided by the user.
26 |
27 | To explain nested BIC search, we need to look into how the algorithm runs.
28 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
29 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
30 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
31 | For each regression problem, we can select the optimal parameters
32 | based on BIC.
33 |
34 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
35 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
36 | current estimate of \emph{u}, and then do the same thing for problem v,
37 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
38 | the above until convergence or the maximal number of iterations has been reached.
39 |
40 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
41 | in the paper cited below.}
42 | }
43 | \description{
44 | This function specifies the value of the \code{u_smooth,v_smooth} arguments in the
45 | \code{moma_*pca} series of functions, and the \code{x_smooth,y_smooth} arguments
46 | in the \code{moma_*cca} and \code{moma_*lda} series of functions.
47 | }
48 |
--------------------------------------------------------------------------------
/man/moma_sparsity_options.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{moma_sparsity_options}
4 | \alias{moma_sparsity_options}
5 | \title{Sparsity-inducing penalty in \code{MoMA}}
6 | \arguments{
7 | \item{...}{Force users to specify arguments by names.}
8 |
9 | \item{lambda}{A vector containing penalty values}
10 |
11 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
12 |
13 | MoMA provides a flexible framework for regularized multivariate analysis
14 | with several tuning parameters for different forms of regularization.
15 | To assist the user in selecting these parameters (\code{alpha_u},
16 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
17 | two selection modes: grid search ("g") and nested BIC search ("b").
18 | Grid search means we solve the problem
19 | for all combinations of parameter values provided by the user.
20 |
21 | To explain nested BIC search, we need to look into how the algorithm runs.
22 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
23 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
24 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
25 | For each regression problem, we can select the optimal parameters
26 | based on BIC.
27 |
28 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
29 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
30 | current estimate of \emph{u}, and then do the same thing for problem v,
31 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
32 | the above until convergence or the maximal number of iterations has been reached.
33 |
34 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
35 | in the paper cited below.}
36 | }
37 | \description{
38 | In the package \code{MoMA}, we support the following sparsity-inducing
39 | penalty functions.
40 | \itemize{
41 | \item{\code{\link{moma_lasso}}}: sparsity
42 | \item{\code{\link{moma_mcp}}}: non-convex sparsity
43 | \item{\code{\link{moma_scad}}}: non-convex sparsity
44 | \item{\code{\link{moma_slope}}}: sparsity
45 | \item{\code{\link{moma_grplasso}}}: group-wise sparsity
46 | \item{\code{\link{moma_fusedlasso}}}: piecewise constant, or ordered fusion
47 | \item{\code{\link{moma_spfusedlasso}}}: sparsity and piece-wise constant
48 | \item{\code{\link{moma_l1tf}}}: piecewise polynomial (default to piecewise linear)
49 | \item{\code{\link{moma_cluster}}}: unordered fusion
50 | }
51 | These functions specify the value of the \code{u_sparse,v_sparse} arguments in the
52 | \code{moma_*pca} series of functions, and the \code{x_sparse,y_sparse} arguments
53 | in the \code{moma_*cca} and \code{moma_*lda} series of functions.
54 | }
55 | \details{
56 | All functions
57 | above share two common parameters: \code{lambda} and \code{select_scheme}, which are
58 | described in the Arguments section.
59 | }
60 | \references{
61 | G. I. Allen and M. Weylandt, "Sparse and Functional Principal
62 | Components Analysis," 2019 IEEE Data Science Workshop (DSW),
63 | Minneapolis, MN, USA, 2019, pp. 11-16. \doi{10.1109/DSW.2019.8755778}.
64 | }
65 |
--------------------------------------------------------------------------------
/man/scad.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{scad}
4 | \alias{scad}
5 | \alias{moma_scad}
6 | \title{SCAD (smoothly clipped absolute deviation)}
7 | \usage{
8 | moma_scad(..., gamma = 3.7, non_negative = FALSE, ..., lambda = 0,
9 | select_scheme = "g")
10 | }
11 | \arguments{
12 | \item{...}{Forces users to specify all arguments by name.}
13 |
14 | \item{gamma}{Non-convexity. Must be larger than 2.}
15 |
16 | \item{non_negative}{A Boolean value. Set to \code{TRUE} to add non-negativity
17 | constraint.}
18 |
19 | \item{lambda}{A vector containing penalty values}
20 |
21 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
22 |
23 | MoMA provides a flexible framework for regularized multivariate analysis
24 | with several tuning parameters for different forms of regularization.
25 | To assist the user in selecting these parameters (\code{alpha_u},
26 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
27 | two selection modes: grid search ("g") and nested BIC search ("b").
28 | Grid search means we solve the problem
29 | for all combinations of parameter values provided by the user.
30 |
31 | To explain nested BIC search, we need to look into how the algorithm runs.
32 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
33 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
34 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
35 | For each regression problem, we can select the optimal parameters
36 | based on BIC.
37 |
38 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
39 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
40 | current estimate of \emph{u}, and then do the same thing for problem v,
41 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
42 | the above until convergence or the maximal number of iterations has been reached.
43 |
44 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
45 | in the paper cited below.}
46 | }
47 | \value{
48 | A \code{moma_sparsity_type} object, which is a list containing the values of \code{non_negative}
49 | and \code{gamma}.
50 | }
51 | \description{
52 | Use this function to set the penalty function to SCAD
53 | \deqn{ P (x; \lambda, \gamma) = \left\{\begin{array}{ll}{
54 | \lambda|x|} & {\text { if }|x| \leq \lambda} \\ {\frac{2 \gamma \lambda|x|-x^{2}-
55 | \lambda^{2}}{2(\gamma-1)}} & {\text { if } \lambda<|x|<\gamma \lambda} \\
56 | {\frac{\lambda^{2}(\gamma+1)}{2}} & {\text { if }|x| \geq \gamma \lambda}\end{array}\right.,}
57 | where \eqn{\lambda} is set by the \code{lambda} argument below.
58 | }
59 | \references{
60 | Fan, Jianqing, and Runze Li. "Variable Selection
61 | via Nonconcave Penalized Likelihood and Its Oracle Properties." Journal of
62 | the American Statistical Association 96.456 (2001): 1348-1360. \doi{10.1198/016214501753382273}.
63 | }
64 |
--------------------------------------------------------------------------------
/man/second_diff_mat.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/util.R
3 | \name{second_diff_mat}
4 | \alias{second_diff_mat}
5 | \title{Second difference matrix}
6 | \usage{
7 | second_diff_mat(n)
8 | }
9 | \arguments{
10 | \item{n}{An integer. The size of the returned matrix.}
11 | }
12 | \description{
13 | This function returns a second difference matrix of size \eqn{n}.
14 | }
15 |
--------------------------------------------------------------------------------
/man/select_scheme.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{select_scheme}
4 | \alias{select_scheme}
5 | \title{Introduction to selection schemes in MoMA}
6 | \description{
7 | Please see the description of the argument \code{select_scheme} in
8 | \code{\link{moma_sparsity_options}}. The \code{select_scheme} argument
9 | presents in functions listed in \code{\link{moma_sparsity_options}}, and the function
10 | \code{\link{moma_smoothness}}.
11 | }
12 |
--------------------------------------------------------------------------------
/man/slope.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{slope}
4 | \alias{slope}
5 | \alias{moma_slope}
6 | \title{SLOPE (sorted \eqn{\ell}-one penalized estimation)}
7 | \usage{
8 | moma_slope(..., lambda = 0, select_scheme = "g")
9 | }
10 | \arguments{
11 | \item{...}{Force users to specify arguments by names.}
12 |
13 | \item{lambda}{A vector containing penalty values}
14 |
15 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
16 |
17 | MoMA provides a flexible framework for regularized multivariate analysis
18 | with several tuning parameters for different forms of regularization.
19 | To assist the user in selecting these parameters (\code{alpha_u},
20 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
21 | two selection modes: grid search ("g") and nested BIC search ("b").
22 | Grid search means we solve the problem
23 | for all combinations of parameter values provided by the user.
24 |
25 | To explain nested BIC search, we need to look into how the algorithm runs.
26 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
27 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
28 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
29 | For each regression problem, we can select the optimal parameters
30 | based on BIC.
31 |
32 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
33 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
34 | current estimate of \emph{u}, and then do the same thing for problem v,
35 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
36 | the above until convergence or the maximal number of iterations has been reached.
37 |
38 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
39 | in the paper cited below.}
40 | }
41 | \value{
42 | A \code{moma_sparsity_type} object, which contains a list containing the string "SLOPE".
43 | }
44 | \description{
45 | Use this function to set the penalty function to SLOPE - Sorted L-One Penalized Estimation
46 | \deqn{\lambda P (x) = \lambda \sum _ { i = 1 } ^ { n } \lambda _ { i } | x | _ { ( i ) } .}
47 | where \eqn{\lambda_i = \Phi ^ { - 1 } ( 1 - q _ { i } ) , q _ { i } = i \cdot q / 2 p, q = 0.05.}
48 | Here \eqn{q} is the false discovery rate (FDR).
49 | }
50 | \references{
51 | Bogdan, Malgorzata, et al. "SLOPE - Adaptive Variable Selection via Convex Optimization."
52 | The Annals of Applied Statistics 9.3 (2015): 1103. \doi{10.1214/15-AOAS842}.
53 | }
54 |
--------------------------------------------------------------------------------
/man/sparse_fused_lasso.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/moma_arguments.R
3 | \name{sparse_fused_lasso}
4 | \alias{sparse_fused_lasso}
5 | \alias{moma_spfusedlasso}
6 | \title{Sparse fused LASSO}
7 | \usage{
8 | moma_spfusedlasso(..., lambda2, ..., lambda = 0, select_scheme = "g")
9 | }
10 | \arguments{
11 | \item{...}{Forces users to specify all arguments by name.}
12 |
13 | \item{lambda2}{A scalar. The level of penalty on the absolute values of the coefficients.
14 | Note that it remains fixed when searching over \code{lambda}, rather than
15 | changes with \code{lambda} in a way that the \code{lambda} / \code{lambda_2}
16 | ratio remains fixed (which is the defualt behavior in the package
17 | \code{glmnet}).}
18 |
19 | \item{lambda}{A vector containing penalty values}
20 |
21 | \item{select_scheme}{A char being either "b" (nested BIC search) or "g" (grid search).
22 |
23 | MoMA provides a flexible framework for regularized multivariate analysis
24 | with several tuning parameters for different forms of regularization.
25 | To assist the user in selecting these parameters (\code{alpha_u},
26 | \code{alpha_v}, \code{lambda_u}, \code{lambda_v}), we provide
27 | two selection modes: grid search ("g") and nested BIC search ("b").
28 | Grid search means we solve the problem
29 | for all combinations of parameter values provided by the user.
30 |
31 | To explain nested BIC search, we need to look into how the algorithm runs.
32 | To find an (approximate) solution to a penalized SVD (Singular Value Decomposition) problem is to solve two
33 | penalized regression problems iteratively. Let's call them problem u and problem v, which give
34 | improving estimates of the right singular vector, \emph{u}, and the left singular vector, \emph{v}, respectively.
35 | For each regression problem, we can select the optimal parameters
36 | based on BIC.
37 |
38 | The nested BIC search is essentially two 2-D searches. We start from SVD solutions, and then find the optimal
39 | parameters for problem u, given current estimate of \emph{v}. Using the result from previous step, update
40 | current estimate of \emph{u}, and then do the same thing for problem v,
41 | that is, to find the optimal parameters for problem v given current estimate of \emph{u}. Repeat
42 | the above until convergence or the maximal number of iterations has been reached.
43 |
44 | Users are welcome to refer to section 3.1: Selection of Regularization Parameters
45 | in the paper cited below.}
46 | }
47 | \value{
48 | A \code{moma_sparsity_type} object, which is a list containing the value of \code{lambda_2}.
49 | }
50 | \description{
51 | Use this function to set the penalty function to sparse fused lasso
52 | \deqn{\lambda \sum | x_{i} - x_{i-1} | + \lambda_2 \sum |x_{i} | ,}
53 | where \eqn{\lambda} is set by the \code{lambda} argument below, and \eqn{\lambda_2}
54 | is specified in by the \code{lambda_2} argument.
55 | }
56 | \references{
57 | Tibshirani, Robert, et al. "Sparsity and Smoothness via the Fused Lasso."
58 | Journal of the Royal Statistical Society: Series B (Statistical Methodology) 67.1 (2005): 91-108.
59 | \doi{10.1111/j.1467-9868.2005.00490.x}.
60 | }
61 |
--------------------------------------------------------------------------------
/src/Makevars:
--------------------------------------------------------------------------------
1 | CXX_STD = CXX11
2 | PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
3 |
4 | strip: $(SHLIB)
5 | if test -e "/usr/bin/strip" & test -e "/bin/uname" & [[ `uname` == "Linux" ]] ; then /usr/bin/strip --strip-debug *.o *.so; fi
6 | if test -e "/usr/bin/strip" & test -e "/bin/uname" & [[ `uname` == "Darwin" ]] ; then /usr/bin/strip -S *.o *.so; fi
7 |
8 | .phony: strip
9 |
--------------------------------------------------------------------------------
/src/Makevars.win:
--------------------------------------------------------------------------------
1 | CXX_STD = CXX11
2 | PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
3 |
--------------------------------------------------------------------------------
/src/moma_base.h:
--------------------------------------------------------------------------------
1 | /* MoMA Base Header
2 | *
3 | * This is where we put all #defines and #includes which will be
4 | * seen by all other headers
5 | */
6 |
7 | #ifndef MOMA_BASE_H
8 | #define MOMA_BASE_H 1
9 |
10 | #include
11 | #include
12 |
13 | // We only include RcppArmadillo.h which pulls Rcpp.h in for us
14 | #include "RcppArmadillo.h"
15 |
16 | // For difficult smoothing matrices, we may encounter artificially small
17 | // eigenvalues: we add a small "nugget" here to regularize the computations
18 | #define MOMA_EIGENVALUE_REGULARIZATION 0.01
19 | static constexpr double MOMA_INFTY = std::numeric_limits::infinity();
20 | static const arma::vec MOMA_EMPTY_GRID_OF_LENGTH1 = -arma::ones(1);
21 | static const double MOMA_FLOATPOINT_EPS = 1e-8;
22 | #define MOMA_FUSEDLASSODP_BUFFERSIZE 5000
23 | enum class DeflationScheme
24 | {
25 | PCA_Hotelling = 1,
26 | CCA = 2,
27 | LDA = 3,
28 | PLS = 4,
29 | PCA_Schur_Complement = 5,
30 | PCA_Projection = 6
31 | };
32 |
33 | enum class SelectionScheme
34 | {
35 | grid = 0,
36 | BIC = 1,
37 | // AIC = 2
38 | // eBIC = 3
39 | };
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/src/moma_fivedlist.cpp:
--------------------------------------------------------------------------------
1 | #include "moma_fivedlist.h"
2 |
3 | RcppFiveDList::RcppFiveDList(int n_alpha_u, int n_lambda_u, int n_alpha_v, int n_lambda_v, int k)
4 | : n_alpha_u(n_alpha_u),
5 | n_lambda_u(n_lambda_u),
6 | n_alpha_v(n_alpha_v),
7 | n_lambda_v(n_lambda_v),
8 | k(k),
9 | flattened_list(n_alpha_u * n_alpha_v * n_lambda_u * n_lambda_v * k)
10 | {
11 | flattened_list.attr("dim") =
12 | Rcpp::NumericVector::create(n_alpha_u, n_lambda_u, n_alpha_v, n_lambda_v, k);
13 | flattened_list.attr("class") = "MoMA_5D_list";
14 | };
15 |
16 | int RcppFiveDList::insert(Rcpp::List object,
17 | int alpha_u_i,
18 | int lambda_u_i,
19 | int alpha_v_i,
20 | int lambda_v_i,
21 | int k_i)
22 | {
23 | // insert object in the alpha_u_i-th position along the alpha_u-axis
24 | // and so on
25 | if (alpha_u_i < 0 || alpha_u_i >= n_alpha_u || lambda_u_i < 0 || lambda_u_i >= n_lambda_u ||
26 | alpha_v_i < 0 || alpha_v_i >= n_alpha_v || lambda_v_i < 0 || lambda_v_i >= n_lambda_v ||
27 | k_i < 0 || k_i >= k)
28 | {
29 | MoMALogger::error("Invalid index is passed to RcppFiveDList::insert. ")
30 | << "Dimension is (" << n_alpha_u << ", " << n_lambda_u << ", " << n_alpha_v << ", "
31 | << n_lambda_v << "," << k << "), received (" << alpha_u_i << ", " << lambda_u_i << ", "
32 | << alpha_v_i << ", " << lambda_v_i << ", " << k_i << ").";
33 | }
34 |
35 | flattened_list(k_i + k * (lambda_v_i +
36 | n_lambda_v * (alpha_v_i +
37 | n_alpha_v * (lambda_u_i + n_lambda_u * (alpha_u_i))))) =
38 | object;
39 | return 0;
40 | }
41 |
42 | Rcpp::List RcppFiveDList::get_list()
43 | {
44 | return flattened_list;
45 | }
46 |
--------------------------------------------------------------------------------
/src/moma_fivedlist.h:
--------------------------------------------------------------------------------
1 | #ifndef moma_fivedlist_H
2 | #define moma_fivedlist_H 1
3 | #include "moma.h"
4 |
5 | class RcppFiveDList
6 | {
7 | int n_alpha_u;
8 | int n_lambda_u;
9 | int n_alpha_v;
10 | int n_lambda_v;
11 | int k;
12 | Rcpp::List flattened_list;
13 |
14 | public:
15 | RcppFiveDList(int n_alpha_u, int n_lambda_u, int n_alpha_v, int n_lambda_v, int k = 1);
16 |
17 | int insert(Rcpp::List object,
18 | int alpha_u_i,
19 | int lambda_u_i,
20 | int alpha_v_i,
21 | int lambda_v_i,
22 | int k_i = 0);
23 |
24 | Rcpp::List get_list();
25 | };
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/src/moma_heap.cpp:
--------------------------------------------------------------------------------
1 | #include "moma_heap.h"
2 | #include "moma_prox_fusion_util.h"
3 |
4 | bool operator>(const HeapNode &left, const HeapNode &right)
5 | {
6 | return left.lambda > right.lambda;
7 | }
8 |
9 | bool gt(const HeapNode &left, const HeapNode &right)
10 | {
11 | return left > right;
12 | }
13 |
14 | Heap::Heap(int n)
15 | {
16 | heap_storage.resize(n);
17 | };
18 |
19 | void Heap::heapify()
20 | {
21 | std::make_heap(heap_storage.begin(), heap_storage.end(), gt);
22 | }
23 |
24 | // Find the smaller child of an element in a heap. Used in siftdown
25 | int Heap::min_child(int i)
26 | {
27 | int cur_size = heap_storage.size();
28 | int child = i * 2 + 1;
29 | if (child >= cur_size)
30 | {
31 | // no children
32 | return NO_CHILD;
33 | }
34 | else if (child + 1 >= cur_size || !(heap_storage[child] > heap_storage[child + 1]))
35 | {
36 | // only child or first child is biggest child
37 | return child;
38 | }
39 | else
40 | {
41 | // second child exists and is smallest child
42 | return child + 1;
43 | }
44 | }
45 |
46 | // TODO: extra copy can be avoided in siftdown
47 | void Heap::swap(int i, int j, FusedGroups *fg)
48 | {
49 | // // DEBUG INFO
50 | MoMALogger::debug("Swapping ") << heap_storage[i].lambda << "and " << heap_storage[j].lambda;
51 | (*fg).g[heap_storage[i].id].map_to_heap = j;
52 | (*fg).g[heap_storage[j].id].map_to_heap = i;
53 | HeapNode tmp = heap_storage[i];
54 | heap_storage[i] = heap_storage[j];
55 | heap_storage[j] = tmp;
56 | }
57 |
58 | // In a min-heap, if the key (lambda in our case) decreases, sift it up
59 | void Heap::siftup(int i, FusedGroups *fg)
60 | {
61 | int parent = (i - 1) / 2;
62 | while (i != 0 && (heap_storage[parent] > heap_storage[i]))
63 | {
64 | Heap::swap(parent, i, fg);
65 | i = parent;
66 | parent = (i - 1) / 2;
67 | }
68 | }
69 |
70 | // In a min-heap, if the key (lambda in our case) increases, sift it down
71 | void Heap::siftdown(int current_node, FusedGroups *fg)
72 | {
73 | int child = min_child(current_node);
74 | while (child != NO_CHILD && (heap_storage[current_node] > heap_storage[child]))
75 | {
76 | Heap::swap(child, current_node, fg);
77 | current_node = child;
78 | child = min_child(child);
79 | }
80 | }
81 |
82 | // Change the key of any nodes;
83 | int Heap::change_lambda_by_id(int i, double new_lambda, FusedGroups *fg)
84 | {
85 | if (i < 0 || i >= heap_storage.size())
86 | {
87 | MoMALogger::error("Try to change lambda: no such id in current heap: ") << i;
88 | }
89 | double old_lambda = heap_storage[i].lambda;
90 | heap_storage[i].lambda = new_lambda;
91 | if (old_lambda < new_lambda)
92 | {
93 | // // DEBUG INFO
94 | // MoMALogger::debug("(") << old_lambda << "," << heap[i].id << ")" << "->"
95 | // << new_lambda << " siftdown";
96 | siftdown(i, fg);
97 | }
98 | else
99 | {
100 | // // DEBUG INFO
101 | // MoMALogger::debug("") << old_lambda << "," << heap[i].id << ")" << "->"
102 | // << new_lambda << " siftup";
103 | siftup(i, fg);
104 | }
105 | return i;
106 | }
107 |
108 | // To delete an element, move it to the tail, pop it out, and then sift down
109 | // the node that replaces it
110 | void Heap::remove(int i, FusedGroups *fg)
111 | {
112 | if (i < 0 || i >= heap_storage.size())
113 | {
114 | MoMALogger::error("Try to delete: no such id in current heap: ") << i;
115 | }
116 | double old_lambda = heap_storage[i].lambda;
117 | Heap::swap(i, heap_storage.size() - 1, fg);
118 | (*fg).g[heap_storage[heap_storage.size() - 1].id].map_to_heap = FusedGroups::NOT_IN_HEAP;
119 | heap_storage.pop_back();
120 | if (old_lambda < heap_storage[i].lambda)
121 | {
122 | siftdown(i, fg);
123 | }
124 | else
125 | {
126 | siftup(i, fg);
127 | }
128 | return;
129 | }
130 |
131 | // Check if an array is a min heap
132 | bool Heap::is_minheap()
133 | {
134 | int i = 0;
135 | while (2 * i + 1 < heap_storage.size())
136 | {
137 | if (heap_storage[i] > heap_storage[2 * i + 1])
138 | {
139 | MoMALogger::warning("Not a min-heap")
140 | << heap_storage[i].lambda << "and" << heap_storage[2 * i + 1].lambda;
141 | return 0;
142 | }
143 | if (2 * i + 2 < heap_storage.size())
144 | {
145 | if (heap_storage[i] > heap_storage[2 * i + 2])
146 | {
147 | MoMALogger::warning("Not a min-heap")
148 | << heap_storage[i].lambda << "and" << heap_storage[2 * i + 2].lambda;
149 | return 0;
150 | }
151 | }
152 | i++;
153 | }
154 | return 1;
155 | }
156 |
157 | bool Heap::is_empty()
158 | {
159 | return heap_storage.size() == 0;
160 | }
161 |
162 | // Get the currently minimun value without deleting the node
163 | HeapNode Heap::heap_peek_min()
164 | {
165 | if (is_empty())
166 | {
167 | MoMALogger::error("You are peaking at an empty heap!");
168 | }
169 | HeapNode n = heap_storage.front();
170 | return n;
171 | }
172 |
173 | // Print the heap
174 | void Heap::heap_print()
175 | {
176 | MoMALogger::debug("") << "(lambda, id)\n";
177 | int cnt = 0;
178 | int thre = 1;
179 | for (auto i : heap_storage)
180 | {
181 | Rcpp::Rcout << i.lambda << ", " << i.id + 1 << "\t";
182 | cnt++;
183 | if (cnt == thre)
184 | {
185 | Rcpp::Rcout << "\n";
186 | thre *= 2;
187 | cnt = 0;
188 | }
189 | }
190 | Rcpp::Rcout << "\n";
191 | }
192 |
--------------------------------------------------------------------------------
/src/moma_heap.h:
--------------------------------------------------------------------------------
1 | #ifndef MOMA_HEAP
2 | #define MOMA_HEAP 1
3 | #include "moma_base.h"
4 | #include "moma_logging.h"
5 |
6 | class HeapNode
7 | {
8 | public:
9 | HeapNode(int i = -1, double l = -1.0) : id(i), lambda(l){};
10 | HeapNode &operator=(const HeapNode &source)
11 | {
12 | id = source.id;
13 | lambda = source.lambda;
14 | return *this;
15 | }
16 | int id; // value: id-th beta
17 | double lambda; // key: for id-th group and its next groupto merge at lambda
18 | void print() { MoMALogger::debug("") << "lambda: " << lambda << "id: " << id; }
19 | };
20 |
21 | // comparision between heap nodes
22 | bool gt(const HeapNode &left, const HeapNode &right);
23 |
24 | class FusedGroups;
25 | class Heap
26 | {
27 | public:
28 | Heap(int n = 0);
29 | void heap_print();
30 | HeapNode heap_peek_min();
31 | bool is_empty();
32 | void heapify();
33 | std::vector heap_storage;
34 | void remove(int id, FusedGroups *fg);
35 |
36 | int change_lambda_by_id(int id, double new_lambda, FusedGroups *fg);
37 | bool is_minheap();
38 |
39 | private:
40 | void swap(int i, int j, FusedGroups *fg);
41 | void siftup(int i, FusedGroups *fg);
42 | void siftdown(int current_node, FusedGroups *fg);
43 |
44 | int min_child(int i);
45 |
46 | // A constant, where the non-existing
47 | // child is assumed to be located.
48 | // Used only in function `min_child`
49 | const int NO_CHILD = -11;
50 | };
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/moma_logging.cpp:
--------------------------------------------------------------------------------
1 | #include "moma.h"
2 |
3 | // [[Rcpp::export]]
4 | void moma_set_logger_level_cpp(int level)
5 | {
6 | auto logger_level = static_cast(level);
7 | MoMALogger::set_level(logger_level);
8 | }
9 |
10 | // [[Rcpp::export]]
11 | int moma_get_logger_level_cpp()
12 | {
13 | auto logger_level = static_cast(MoMALogger::get_level());
14 | return logger_level;
15 | }
16 |
17 | // [[Rcpp::export]]
18 | void moma_log_cpp(int level, Rcpp::StringVector x)
19 | {
20 | auto msg_level = static_cast(level);
21 | std::string msg = Rcpp::as(x[0]);
22 | if (msg_level >= MoMALoggerLevel::ERRORS)
23 | {
24 | MoMALogger::error(msg);
25 | }
26 | else if (msg_level >= MoMALoggerLevel::WARNING)
27 | {
28 | MoMALogger::warning(msg);
29 | }
30 | else if (msg_level >= MoMALoggerLevel::MESSAGES)
31 | {
32 | MoMALogger::message(msg);
33 | }
34 | else if (msg_level >= MoMALoggerLevel::INFO)
35 | {
36 | MoMALogger::info(msg);
37 | }
38 | else if (msg_level >= MoMALoggerLevel::DEBUG)
39 | {
40 | MoMALogger::debug(msg);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/moma_prox_flsadp.h:
--------------------------------------------------------------------------------
1 | #ifndef MOMA_PROX_FLSADP
2 | #define MOMA_PROX_FLSADP 1
3 |
4 | #include "moma_base.h"
5 |
6 | // Copyright (c) 2012, Nicholas A. Johnson
7 | // All rights reserved.
8 |
9 | // Redistribution and use in source and binary forms, with or without
10 | // modification, are permitted provided that the following conditions are met:
11 | // 1. Redistributions of source code must retain the above copyright
12 | // notice, this list of conditions and the following disclaimer.
13 | // 2. Redistributions in binary form must reproduce the above copyright
14 | // notice, this list of conditions and the following disclaimer in the
15 | // documentation and/or other materials provided with the distribution.
16 | // 3. All advertising materials mentioning features or use of this software
17 | // must display the following acknowledgement:
18 | // This product includes software developed by Nicholas A. Johnson.
19 | // 4. Neither the name of Nicholas A. Johnson nor the
20 | // names of its contributors may be used to endorse or promote products
21 | // derived from this software without specific prior written permission.
22 |
23 | // THIS SOFTWARE IS PROVIDED BY Nicholas A. Johnson ''AS IS'' AND ANY
24 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 | // DISCLAIMED. IN NO EVENT SHALL Nicholas A. Johnson BE LIABLE FOR ANY
27 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 |
34 | // This file is an adapted version of the package cited above.
35 | // Better modularity and readability. Commments are added
36 | // in order to explain the algorithm. Avoid explicit
37 | // memory management.
38 |
39 | // Reference:
40 | // Johnson, Nicholas A.
41 | // "A dynamic programming algorithm for the fused lasso and l 0-segmentation."
42 | // Journal of Computational and Graphical Statistics 22.2 (2013): 246-260.
43 |
44 | struct MsgElt
45 | {
46 | // the location of the knot
47 | double x_;
48 | // the sign variable that tells us
49 | // whether this was a left or right end-point of the
50 | // segment
51 | bool sgn_;
52 | // a delta which can be used to reconstruct the function
53 | // if we move from the first knot to the last or from
54 | // the last to the first
55 | double lin_;
56 | double quad_;
57 | };
58 |
59 | class Msg
60 | {
61 | public:
62 | std::vector buf_;
63 | arma::vec back_pointers;
64 | int start_idx_;
65 | int len_;
66 |
67 | MsgElt init_knot_;
68 | MsgElt end_knot_;
69 |
70 | void InitMsg(int n, int init_sz, double lin, double quad, double lambda2);
71 | void UpdMsg(double lambda2, double lin, double quad, int bp_idx);
72 | void UpdMsgOpt(double lambda2, double lin, double quad, int bp_idx);
73 | double Argmax(double *max_val);
74 |
75 | // This data structure supports prepend and append;
76 | // To implement this, first allocate a long array,
77 | // then start filling data in the middle and extend to both ends. Shift
78 | // the space filled with data towards the center of the array periodically
79 | void ShiftMsg(int check_freq);
80 | arma::vec BackTrace(int seq_len, double last_msg_max);
81 | };
82 |
83 | arma::vec myflsadp(const arma::vec &x,
84 | double lambda2,
85 | int init_buf_sz = MOMA_FUSEDLASSODP_BUFFERSIZE);
86 |
87 | #endif // MOMA_PROX_FLSADP
88 |
--------------------------------------------------------------------------------
/src/moma_prox_fusion_util.h:
--------------------------------------------------------------------------------
1 | #ifndef MOMA_PROX_FUSION_UTIL
2 | #define MOMA_PROX_FUSION_UTIL 1
3 | #include "moma_base.h"
4 | #include "moma_heap.h"
5 | class FusedGroups;
6 | class Group
7 | {
8 | public:
9 | // range of the group, note they are continuous
10 | int head;
11 | int tail;
12 | // When two groups (say A and B) merge,
13 | // `parent` of the last node of group B will point to A
14 | // Note all nodes are initialized with `parent` pointing to itself
15 | int parent;
16 | // The following infomation is valid only when `parent` points to itself
17 | double lambda;
18 | double beta;
19 | double slope;
20 | int map_to_heap;
21 | friend class FusedGroups;
22 | Group(int h = -1,
23 | int t = -1,
24 | int p = -1,
25 | double lambda = -1,
26 | double beta = -1,
27 | double slope = 0)
28 | : head(h), tail(t), parent(p), lambda(lambda), beta(beta), slope(slope){};
29 | void print()
30 | {
31 | MoMALogger::debug("") << "[" << head << "," << tail << "] map_to_heap: " << map_to_heap
32 | << "(lambda:" << lambda << ",beta:" << beta << ",slope: " << slope
33 | << ")";
34 | }
35 | };
36 |
37 | class FusedGroups
38 | {
39 | public:
40 | // Constructor
41 | FusedGroups(const arma::vec &x);
42 | // Merge the next two nodes.
43 | // Note if multiple pairs of nodes is to be merged at the same lambda, only
44 | // one pair will be merged
45 | void merge();
46 | // Return the next lambda at which merge happens
47 | double next_lambda();
48 | // Check if all beta's are merged
49 | bool all_merged();
50 | // Evaluate beta by extending the lines
51 | arma::vec find_beta_at(double target_lam);
52 |
53 | // Manipulation on a group
54 | void print();
55 | bool is_valid(int this_node);
56 | int pre_group(int this_group);
57 | int next_group(int this_group);
58 | int group_size(int this_group);
59 |
60 | // Calculation concerning lines
61 | double line_value_at(double x, double y, double slope, double x_);
62 | double lines_meet_at(double x1, double x2, double k1, double k2, double y1, double y2);
63 |
64 | // Some constants
65 | // Used when the group includes beta_1
66 | const int NO_PRE = -2;
67 | // Used when the group includes beta_p
68 | const int NO_NEXT = -3;
69 | static const int NOT_IN_HEAP = -4;
70 | // This constant is used in the function
71 | // lines_meet_at, where we might bump
72 | // into situation that the two lines are
73 | // parallel. In order to deal with this,
74 | // we return MOMA_INFTY.
75 |
76 | // A vector stroing all the beta values
77 | std::vector g;
78 | Heap heap;
79 | };
80 | #endif
81 |
--------------------------------------------------------------------------------
/src/moma_prox_sortedL1.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, M. Bogdan, E. van den Berg, W. Su, and E.J. Candes
3 | *
4 | * This file is part of SLOPE Toolbox version 1.0.
5 | *
6 | * The SLOPE Toolbox is free software: you can redistribute it
7 | * and/or modify it under the terms of the GNU General Public License
8 | * as published by the Free Software Foundation, either version 3 of
9 | * the License, or (at your option) any later version.
10 | *
11 | * The SLOPE Toolbox is distributed in the hope that it will
12 | * be useful, but WITHOUT ANY WARRANTY; without even the implied
13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 | * See the GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with the SLOPE Toolbox. If not, see
18 | * .
19 | */
20 |
21 | #include "moma_prox_sortedL1.h"
22 | #include "moma_logging.h"
23 |
24 | // This is a slight modified version of the code provided by
25 | // M. Bogdan, E. van den Berg, W. Su, and E.J. Candes
26 | // http://statweb.stanford.edu/~candes/SortedL1/
27 |
28 | int evaluateProx(const arma::vec &y,
29 | const arma::vec &lambda,
30 | arma::vec &x,
31 | int n,
32 | const arma::uvec &order)
33 | {
34 | double d;
35 |
36 | arma::vec s(n);
37 | arma::vec w(n);
38 | arma::uvec idx_i(n);
39 | arma::uvec idx_j(n);
40 |
41 | int i, j, k;
42 |
43 | k = 0;
44 | for (i = 0; i < n; i++)
45 | {
46 | idx_i(k) = i;
47 | idx_j(k) = i;
48 | s(k) = y(i) - lambda(i);
49 | w(k) = s(k);
50 |
51 | while ((k > 0) && (w[k - 1] <= w(k)))
52 | {
53 | k--;
54 | idx_j(k) = i;
55 | s(k) += s[k + 1];
56 | w(k) = s(k) / (i - idx_i(k) + 1);
57 | }
58 |
59 | k++;
60 | }
61 |
62 | for (j = 0; j < k; j++)
63 | {
64 | d = w(j);
65 | if (d < 0)
66 | {
67 | d = 0;
68 | }
69 | for (i = idx_i(j); i <= idx_j(j); i++)
70 | {
71 | x[order(i)] = d;
72 | }
73 | }
74 |
75 | return 0;
76 | }
77 |
--------------------------------------------------------------------------------
/src/moma_prox_sortedL1.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013, M. Bogdan, E. van den Berg, W. Su, and E.J. Candes
3 | *
4 | * This file is part of SLOPE Toolbox version 1.0.
5 | *
6 | * The SLOPE Toolbox is free software: you can redistribute it
7 | * and/or modify it under the terms of the GNU General Public License
8 | * as published by the Free Software Foundation, either version 3 of
9 | * the License, or (at your option) any later version.
10 | *
11 | * The SLOPE Toolbox is distributed in the hope that it will
12 | * be useful, but WITHOUT ANY WARRANTY; without even the implied
13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 | * See the GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with the SLOPE Toolbox. If not, see
18 | * .
19 | */
20 |
21 | #ifndef MOMA_PROX_SORTEDL1
22 | #define MOMA_PROX_SORTEDL1 1
23 |
24 | #include "moma_base.h"
25 |
26 | int evaluateProx(const arma::vec &y,
27 | const arma::vec &lambda,
28 | arma::vec &x,
29 | int n,
30 | const arma::uvec &order);
31 | #endif // MOMA_PROX_SORTEDL1
32 |
--------------------------------------------------------------------------------
/src/moma_solver.h:
--------------------------------------------------------------------------------
1 | // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil;
2 | // -*-
3 |
4 | #ifndef MOMA_SOLVER
5 | #define MOMA_SOLVER 1
6 |
7 | #include "moma_base.h"
8 | #include "moma_logging.h"
9 | #include "moma_prox.h"
10 |
11 | // Penalized regression solver
12 | // min_u || y - u || + lambda * P(u) s.t. || u ||_S <= 1
13 | // S = I + alpha * Omega
14 | class _PR_solver
15 | {
16 | protected:
17 | int dim; // dimension of the PR problem
18 | double lambda;
19 | double alpha;
20 | double L;
21 | const arma::mat Ω
22 | // S = I + alpha * Omega for u, v smoothing
23 | arma::mat S;
24 | bool is_S_idmat; // indicator of alpha == 0.0 <=> S == I
25 |
26 | // Step size for proximal gradient algorithm
27 | // - since this is a linear model internally, we can used a fixed
28 | // step size without backtracking
29 | double grad_step_size;
30 | double prox_step_size;
31 | // A proximal operator for sparsity inducing penalties
32 | //
33 | // Note that currently the threshold level is not defined in the Prox object
34 | ProxOp p;
35 | // A gradient operator
36 | arma::vec g(const arma::vec &v,
37 | const arma::vec &y,
38 | double step_size,
39 | const arma::mat &S,
40 | bool is_S_idmat);
41 | arma::vec normalize(const arma::vec &u);
42 |
43 | // user-specified precision and max iterations
44 | double EPS;
45 | int MAX_ITER;
46 |
47 | public:
48 | explicit _PR_solver(
49 | // smoothness
50 | double i_alpha,
51 | const arma::mat &i_Omega,
52 | // sparsity
53 | double i_lambda,
54 | Rcpp::List prox_arg_list,
55 | // algorithm settings
56 | double i_EPS,
57 | int i_MAX_ITER,
58 | int i_dim);
59 |
60 | // Used when solving for a bunch of lambda's and alpha's
61 | int set_penalty(double new_lambda, double new_alpha);
62 | double bic(arma::vec y, const arma::vec &est);
63 | virtual ~_PR_solver() = default;
64 | virtual arma::vec solve(arma::vec y, const arma::vec &start_point) = 0;
65 | void check_convergence(int iter, double tol);
66 | };
67 |
68 | class ISTA : public _PR_solver
69 | {
70 | public:
71 | ISTA(double i_alpha,
72 | const arma::mat &i_Omega,
73 | double i_lambda,
74 | Rcpp::List prox_arg_list,
75 | double i_EPS,
76 | int i_MAX_ITER,
77 | int dim)
78 | : _PR_solver(i_alpha, i_Omega, i_lambda, prox_arg_list, i_EPS, i_MAX_ITER, dim)
79 | {
80 | MoMALogger::debug("Initializing a ISTA solver.");
81 | };
82 | arma::vec solve(arma::vec y, const arma::vec &start_point);
83 | ~ISTA() { MoMALogger::debug("Releasing a ISTA object"); }
84 | };
85 |
86 | class FISTA : public _PR_solver
87 | {
88 | public:
89 | FISTA(double i_alpha,
90 | const arma::mat &i_Omega,
91 | double i_lambda,
92 | Rcpp::List prox_arg_list,
93 | double i_EPS,
94 | int i_MAX_ITER,
95 | int dim)
96 | : _PR_solver(i_alpha, i_Omega, i_lambda, prox_arg_list, i_EPS, i_MAX_ITER, dim)
97 | {
98 | MoMALogger::debug("Initializing a FISTA solver.");
99 | };
100 | arma::vec solve(arma::vec y, const arma::vec &start_point);
101 | ~FISTA() { MoMALogger::debug("Releasing a FISTA object"); }
102 | };
103 |
104 | class OneStepISTA : public _PR_solver
105 | {
106 | public:
107 | OneStepISTA(double i_alpha,
108 | const arma::mat &i_Omega,
109 | double i_lambda,
110 | Rcpp::List prox_arg_list,
111 | double i_EPS,
112 | int i_MAX_ITER,
113 | int dim)
114 | : _PR_solver(i_alpha, i_Omega, i_lambda, prox_arg_list, i_EPS, i_MAX_ITER, dim)
115 | {
116 | MoMALogger::debug("Initializing an one-step ISTA solver.");
117 | };
118 | arma::vec solve(arma::vec y, const arma::vec &start_point);
119 | ~OneStepISTA() { MoMALogger::debug("Releasing a OneStepISTA object"); }
120 | };
121 |
122 | // A handle class
123 | class PR_solver
124 | {
125 | private:
126 | _PR_solver *prs;
127 |
128 | public:
129 | PR_solver(
130 | // a string saying which algorithm to use
131 | const std::string &algorithm_string,
132 | // same as class _PR_solver
133 | double i_alpha,
134 | const arma::mat &i_Omega,
135 | double i_lambda,
136 | Rcpp::List prox_arg_list,
137 | double i_EPS,
138 | int i_MAX_ITER,
139 | int dim);
140 |
141 | // wrap operations in _PR_solver class
142 | arma::vec solve(arma::vec y, const arma::vec &start_point);
143 | double bic(arma::vec y, const arma::vec &est);
144 | int set_penalty(double new_lambda, double new_alpha);
145 |
146 | ~PR_solver() { delete prs; }
147 | };
148 |
149 | #endif
150 |
--------------------------------------------------------------------------------
/src/moma_solver_BICsearch.cpp:
--------------------------------------------------------------------------------
1 | #include "moma_solver_BICsearch.h"
2 |
3 | void BIC_searcher::bind(PR_solver *object, Criterion method)
4 | {
5 | pr_solver = object;
6 | cri = method;
7 | }
8 |
9 | double BIC_searcher::cur_criterion(arma::vec y, const arma::vec &est)
10 | {
11 | return (pr_solver->*cri)(y, est);
12 | }
13 |
14 | // Return a Rcpp::List:
15 | // Rcpp::Named("lambda") = opt_lambda_u,
16 | // Rcpp::Named("alpha") = opt_alpha_u,
17 | // Rcpp::Named("vector") = working_selected_u,
18 | // Rcpp::Named("bic") = minbic_u
19 | Rcpp::List BIC_searcher::search(const arma::vec &y, // min_{u} || y - u || + ...penalty...
20 | const arma::vec &initial_u, // start point
21 | const arma::vec &alpha_u,
22 | const arma::vec &lambda_u)
23 | {
24 | arma::vec working_selected_u;
25 | arma::vec working_u = initial_u;
26 | double working_bic_u;
27 | double minbic_u = MOMA_INFTY;
28 | double opt_alpha_u;
29 | double opt_lambda_u;
30 | for (int i = 0; i < alpha_u.n_elem; i++)
31 | {
32 | // Put lambda_u in the inner loop to avoid reconstructing S many times
33 | for (int j = 0; j < lambda_u.n_elem; j++)
34 | {
35 | pr_solver->set_penalty(lambda_u(j), alpha_u(i));
36 | // working_u is the solution of the previous problem
37 | working_u = pr_solver->solve(y, working_u);
38 | working_bic_u = cur_criterion(y, working_u);
39 | MoMALogger::debug("(curBIC, minBIC, lambda, alpha) = (")
40 | << working_bic_u << "," << minbic_u << "," << lambda_u(j) << "," << alpha_u(i)
41 | << ")";
42 | if (working_bic_u < minbic_u)
43 | {
44 | minbic_u = working_bic_u;
45 | working_selected_u = working_u;
46 | opt_lambda_u = lambda_u(j);
47 | opt_alpha_u = alpha_u(i);
48 | }
49 | }
50 | }
51 | MoMALogger::debug("Finish greedy BIC, chosen (minBIC, alpha, lambda) = (")
52 | << minbic_u << ", " << opt_alpha_u << ", " << opt_lambda_u << ").";
53 |
54 | return Rcpp::List::create(
55 | Rcpp::Named("lambda") = opt_lambda_u, Rcpp::Named("alpha") = opt_alpha_u,
56 | Rcpp::Named("vector") = working_selected_u, Rcpp::Named("bic") = minbic_u);
57 | };
58 |
--------------------------------------------------------------------------------
/src/moma_solver_BICsearch.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef MOMA_SOLVER_BICSEARCH_H
3 | #define MOMA_SOLVER_BICSEARCH_H 1
4 |
5 | #include "moma_base.h"
6 | #include "moma_logging.h"
7 | #include "moma_solver.h"
8 |
9 | class BIC_searcher
10 | {
11 | public:
12 | typedef double (PR_solver::*Criterion)(arma::vec y, const arma::vec &est);
13 | BIC_searcher(){};
14 |
15 | void bind(PR_solver *object, Criterion method);
16 |
17 | // current criterion
18 | double cur_criterion(arma::vec y, const arma::vec &est);
19 |
20 | ~BIC_searcher()
21 | {
22 | // No need to delete pr_solver
23 | MoMALogger::debug("Releasing a BIC_searcher object");
24 | }
25 |
26 | Rcpp::List search(const arma::vec &y, // min_{u} || y - u || + ...penalty...
27 | const arma::vec &u, // start point
28 | const arma::vec &alpha_u,
29 | const arma::vec &lambda_u);
30 |
31 | private:
32 | PR_solver *pr_solver;
33 | Criterion cri;
34 | };
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/src/moma_test_expose.cpp:
--------------------------------------------------------------------------------
1 | #include "moma.h"
2 | #include "moma_prox.h"
3 | #include "moma_solver.h"
4 |
5 | // [[Rcpp::export]]
6 | arma::vec test_prox_lasso(const arma::vec &x, double l)
7 | {
8 | Lasso a;
9 | return a(x, l);
10 | }
11 |
12 | // [[Rcpp::export]]
13 | arma::vec test_prox_nnlasso(const arma::vec &x, double l)
14 | {
15 | NonNegativeLasso a;
16 | return a(x, l);
17 | }
18 |
19 | // [[Rcpp::export]]
20 | arma::vec test_prox_scad(const arma::vec &x, double l, double gamma = 3.7)
21 | {
22 | SCAD a(gamma);
23 | return a(x, l);
24 | }
25 |
26 | // [[Rcpp::export]]
27 | arma::vec test_prox_scadvec(const arma::vec &x, double l, double gamma = 3.7)
28 | {
29 | SCAD a(gamma);
30 | return a.vec_prox(x, l);
31 | }
32 |
33 | // [[Rcpp::export]]
34 | arma::vec test_prox_nnscad(const arma::vec &x, double l, double gamma = 3.7)
35 | {
36 | NonNegativeSCAD a(gamma);
37 | return a(x, l);
38 | }
39 |
40 | // [[Rcpp::export]]
41 | arma::vec test_prox_mcp(const arma::vec &x, double l, double gamma = 4)
42 | {
43 | MCP a(gamma);
44 | return a(x, l);
45 | }
46 |
47 | // [[Rcpp::export]]
48 | arma::vec test_prox_mcpvec(const arma::vec &x, double l, double gamma = 4)
49 | {
50 | MCP a(gamma);
51 | return a.vec_prox(x, l);
52 | }
53 |
54 | // [[Rcpp::export]]
55 | arma::vec test_prox_nnmcp(const arma::vec &x, double l, double gamma = 4)
56 | {
57 | NonNegativeMCP a(gamma);
58 | return a(x, l);
59 | }
60 |
61 | // [[Rcpp::export]]
62 | arma::vec test_prox_grplasso(const arma::vec &x, const arma::vec &g, double l)
63 | {
64 | GrpLasso a(g);
65 | return a(x, l);
66 | }
67 |
68 | // [[Rcpp::export]]
69 | arma::vec test_prox_nngrplasso(const arma::vec &x, const arma::vec &g, double l)
70 | {
71 | NonNegativeGrpLasso a(g);
72 | return a(x, l);
73 | }
74 |
75 | // [[Rcpp::export]]
76 | arma::vec test_prox_fusedlassopath(const arma::vec &x, double l)
77 | {
78 | OrderedFusedLasso a;
79 | return a(x, l);
80 | }
81 |
82 | // [[Rcpp::export]]
83 | arma::vec test_prox_fusedlassodp(const arma::vec &x, double l)
84 | {
85 | OrderedFusedLassoDP a;
86 | return a(x, l);
87 | }
88 |
89 | // [[Rcpp::export]]
90 | arma::vec test_prox_spfusedlasso(const arma::vec &x, double l, double lambda2)
91 | {
92 | // lambda2: the level of penalty on
93 | // the absolute values of the coefficients
94 | SparseFusedLasso a(lambda2);
95 | return a(x, l);
96 | }
97 |
98 | // [[Rcpp::export]]
99 | arma::vec test_prox_fusion(const arma::vec &x,
100 | double l,
101 | const arma::mat w,
102 | bool ADMM,
103 | bool acc,
104 | double prox_eps = 1e-10)
105 | {
106 | Fusion a(w, ADMM, acc, prox_eps);
107 | return a(x, l);
108 | }
109 |
110 | // [[Rcpp::export]]
111 | arma::vec test_prox_l1gf(const arma::vec &x, double l, int k = 1)
112 | {
113 | L1TrendFiltering a(x.n_elem, k);
114 | return a(x, l);
115 | }
116 |
117 | // [[Rcpp::export]]
118 | arma::vec test_prox_slope(const arma::vec &x, double l)
119 | {
120 | // lambda2: the level of penalty on
121 | // the absolute values of the coefficients
122 | SLOPE a(x.n_elem);
123 | return a(x, l);
124 | }
125 |
126 | // [[Rcpp::export]]
127 | int test_df_orderedfusion(const arma::vec &x)
128 | {
129 | OrderedFusedLasso a;
130 | return a.df(x);
131 | }
132 |
133 | // [[Rcpp::export]]
134 | int test_df_spfusedlasso(const arma::vec &x)
135 | {
136 | // SparseFusedLasso object needs a `lambda2` argument
137 | // (the level of penalty on the absolute values of
138 | // the coefficients) to initialize
139 | SparseFusedLasso a(1);
140 | return a.df(x);
141 | }
142 |
143 | // [[Rcpp::export]]
144 | int test_df_l1gf(const arma::vec &x, int k = 1)
145 | {
146 | L1TrendFiltering a(x.n_elem, k);
147 | return a.df(x);
148 | }
149 |
150 | // [[Rcpp::export]]
151 | int test_df_grplasso(const arma::vec &x, const arma::vec &g)
152 | {
153 | GrpLasso a(g);
154 | return a.df(x);
155 | }
156 |
157 | // [[Rcpp::export]]
158 | double test_BIC(const arma::vec y,
159 | const arma::vec y_est,
160 | const std::string &algorithm_string,
161 | double i_alpha,
162 | const arma::mat &i_Omega,
163 | double i_lambda,
164 | Rcpp::List prox_arg_list,
165 | int dim,
166 | double i_EPS = 1e-6,
167 | int i_MAX_ITER = 1e+3)
168 | {
169 | PR_solver solver(algorithm_string, i_alpha, i_Omega, i_lambda, prox_arg_list, i_EPS, i_MAX_ITER,
170 | dim);
171 |
172 | return solver.bic(y, y_est);
173 | }
174 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(MoMA)
3 |
4 | test_check("MoMA")
5 |
--------------------------------------------------------------------------------
/tests/testthat/helper_moma_tests.R:
--------------------------------------------------------------------------------
1 | library(MoMA)
2 | library(stringr)
3 |
4 | expect_no_error <- function(object, ..., all = FALSE, info = NULL, label = NULL) {
5 | expect_error(object, regexp = NA, ..., all = all, info = info, label = label)
6 | }
7 |
8 | expect_no_warning <- function(object, ..., all = FALSE, info = NULL, label = NULL) {
9 | expect_warning(object, regexp = NA, ..., all = all, info = info, label = label)
10 | }
11 |
12 | expect_no_message <- function(object, ..., all = FALSE, info = NULL, label = NULL) {
13 | expect_message(object, regexp = NA, ..., all = all, info = info, label = label)
14 | }
15 |
16 | expect_str_contains <- function(object, expected, info = NULL, label = NULL) {
17 | if (!is.character(object)) object <- as.character(object)
18 | if (!is.character(expected)) expected <- as.character(expected)
19 |
20 | expect_true(all(str_detect(object, expected)),
21 | info = info, label = label
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/tests/testthat/test_5Dlist_extractor.R:
--------------------------------------------------------------------------------
1 | context("5D List")
2 |
3 | set.seed(123)
4 | X <- matrix(runif(12), 3, 4) * 10
5 |
6 | # They are mutually prime. This is useful for testing
7 | # the size of the 5D list
8 | n_alpha_u <- 7
9 | n_alpha_v <- 5
10 | n_lambda_u <- 3
11 | n_lambda_v <- 2
12 | rank <- 3
13 |
14 | # Penalties should not be too high. Otherwise
15 | # u and v becomes vectors of zeros, and defaltion
16 | # is thus trivial.
17 | alpha_u <- seq(0, 0.1, length.out = n_alpha_u)
18 | alpha_v <- seq(0, 0.2, length.out = n_alpha_v)
19 | lambda_u <- seq(0, 0.3, length.out = n_lambda_u)
20 | lambda_v <- seq(0, 0.4, length.out = n_lambda_v)
21 |
22 |
23 | public_arg_list <- c(
24 | list(
25 | X = X,
26 | alpha_u = alpha_u, alpha_v = alpha_v,
27 | Omega_u = second_diff_mat(3), Omega_v = second_diff_mat(4),
28 | lambda_u = lambda_u, lambda_v = lambda_v,
29 | prox_arg_list_u = add_default_prox_args(lasso()), prox_arg_list_v = add_default_prox_args(empty()),
30 | rank = rank
31 | ),
32 | moma_pg_settings()
33 | )
34 |
35 | # Generate a 5-D list by calling `cpp_multirank_BIC_grid_search`
36 | five_D_list_instance <- do.call(
37 | cpp_multirank_BIC_grid_search,
38 | c(
39 | public_arg_list,
40 | list(
41 | select_scheme_alpha_u = 0, # grid
42 | select_scheme_alpha_v = 0, # grid
43 | select_scheme_lambda_u = 0, # grid
44 | select_scheme_lambda_v = 0 # grid
45 | )
46 | )
47 | )
48 |
49 | test_that("Test 5D List attribute", {
50 | expect_true(inherits(five_D_list_instance, "MoMA_5D_list"))
51 | })
52 |
53 |
54 | test_that("Error on receiving non-MoMA_5D_list object", {
55 | expect_error(
56 | get_5Dlist_elem(c(1), 1, 1, 1, 1),
57 | paste0(sQuote("x"), " should be a ", sQuote("MoMA_5D_list"), " object")
58 | )
59 | })
60 |
61 |
62 | test_that("Access all elements", {
63 | # dim(five_D_list_instance) = 7 3 5 2
64 | # n_alpha_u=7; n_alpha_v=5; n_lambda_u=3; n_lambda_v=2; # mutually prime
65 | cnt <- 1
66 | for (i in 1:n_alpha_u) {
67 | for (j in 1:n_lambda_u) {
68 | for (k in 1:n_alpha_v) {
69 | for (l in 1:n_lambda_v) {
70 | for (rk in 1:rank) {
71 | expect_true(!(is.null(five_D_list_instance[[cnt]])))
72 | expect_equal(
73 | get_5Dlist_elem(five_D_list_instance, i, j, k, l, rk)[[1]],
74 | five_D_list_instance[[cnt]]
75 | )
76 | cnt <- cnt + 1
77 | }
78 | }
79 | }
80 | }
81 | }
82 | })
83 |
84 | test_that("No error when accessing the broundary", {
85 | expect_no_error(get_5Dlist_elem(five_D_list_instance, n_alpha_u, n_lambda_u, n_alpha_v, n_lambda_v, rank))
86 | })
87 |
88 | test_that("Error when just crossing the broundary", {
89 | # NOTE: R index starts from 1
90 |
91 | # Lower boundary
92 | expect_error(
93 | get_5Dlist_elem(five_D_list_instance, n_alpha_u, n_lambda_u, n_alpha_v, 0),
94 | "Invalid index \\(7,3,5,0,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
95 | )
96 |
97 | expect_error(
98 | get_5Dlist_elem(five_D_list_instance, n_alpha_u, n_lambda_u, 0, n_lambda_v),
99 | "Invalid index \\(7,3,0,2,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
100 | )
101 |
102 | expect_error(
103 | get_5Dlist_elem(five_D_list_instance, n_alpha_u, 0, n_alpha_v, n_lambda_v),
104 | "Invalid index \\(7,0,5,2,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
105 | )
106 |
107 | expect_error(
108 | get_5Dlist_elem(five_D_list_instance, 0, n_lambda_u, n_alpha_v, n_lambda_v),
109 | "Invalid index \\(0,3,5,2,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
110 | )
111 |
112 | # Upper boundary
113 | expect_error(
114 | get_5Dlist_elem(five_D_list_instance, n_alpha_u, n_lambda_u, n_alpha_v, n_lambda_v + 1),
115 | "Invalid index \\(7,3,5,3,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
116 | )
117 |
118 | expect_error(
119 | get_5Dlist_elem(five_D_list_instance, n_alpha_u, n_lambda_u, n_alpha_v + 1, n_lambda_v),
120 | "Invalid index \\(7,3,6,2,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
121 | )
122 |
123 | expect_error(
124 | get_5Dlist_elem(five_D_list_instance, n_alpha_u, n_lambda_u + 1, n_alpha_v, n_lambda_v),
125 | "Invalid index \\(7,4,5,2,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
126 | )
127 |
128 | expect_error(
129 | get_5Dlist_elem(five_D_list_instance, n_alpha_u + 1, n_lambda_u, n_alpha_v, n_lambda_v),
130 | "Invalid index \\(8,3,5,2,1\\), dim = c\\(7, 3, 5, 2, 3\\)"
131 | )
132 | })
133 |
--------------------------------------------------------------------------------
/tests/testthat/test_BIC.R:
--------------------------------------------------------------------------------
1 | context("BIC tests")
2 |
3 | bic_lasso <- function(y, y_est) {
4 | p <- length(y)
5 | res <- norm(as.matrix(y - y_est), "2")
6 | df <- sum(y_est != 0)
7 | bic <- log(res * res / p) + log(p) / p * df
8 | return(bic)
9 | }
10 |
11 | test_that("Test for lasso BIC", {
12 | y <- c(1, 2, 3)
13 | y_est <- c(2, 2, 2)
14 | p <- length(y)
15 | expect_equal(test_BIC(
16 | y, y_est,
17 | "ISTA",
18 | 0, second_diff_mat(p),
19 | 0, add_default_prox_args(lasso()),
20 | p
21 | ), bic_lasso(y, y_est))
22 | })
23 |
--------------------------------------------------------------------------------
/tests/testthat/test_MBG-single_problem.R:
--------------------------------------------------------------------------------
1 | context("`cpp_multirank_BIC_grid_search` as solving a single problem")
2 |
3 | set.seed(123)
4 | X <- matrix(runif(12), 3, 4) * 10
5 |
6 | # They are mutually prime. This is useful for testing
7 | # the size of the 5D list
8 | n_alpha_u <- 7
9 | n_alpha_v <- 5
10 | n_lambda_u <- 5
11 | n_lambda_v <- 5
12 | rank <- 1
13 |
14 | # Penalties should not be too high. Otherwise
15 | # u and v becomes vectors of zeros, and defaltion
16 | # is thus trivial.
17 | alpha_u <- seq(0, 10, length.out = n_alpha_u)
18 | alpha_v <- seq(0, 10, length.out = n_alpha_v)
19 | lambda_u <- seq(0, 10, length.out = n_lambda_u)
20 | lambda_v <- seq(0, 10, length.out = n_lambda_v)
21 |
22 | # public_arglist_wo_penalty does not specify
23 | public_arglist_wo_penalty <- c(
24 | list(
25 | X = X,
26 | # alpha_u = alpha_u, alpha_v = alpha_v,
27 | Omega_u = second_diff_mat(3), Omega_v = second_diff_mat(4),
28 | # lambda_u = lambda_u, lambda_v = lambda_v,
29 | prox_arg_list_u = add_default_prox_args(lasso()),
30 | prox_arg_list_v = add_default_prox_args(lasso()),
31 | rank = 1
32 | ),
33 | moma_pg_settings()
34 | )
35 |
36 | # Tests for greedy BIC
37 | test_that("`cpp_multirank_BIC_grid_search` solves a single MoMA problem", {
38 | # four grid requests
39 |
40 | zero_cnt <- 0
41 |
42 | for (av in alpha_v) {
43 | for (au in alpha_u) {
44 | for (lv in lambda_v) {
45 | for (lu in lambda_u) {
46 | public_arglist_w_penalty <- c(
47 | public_arglist_wo_penalty,
48 | list(
49 | alpha_u = au,
50 | alpha_v = av,
51 | lambda_u = lu,
52 | lambda_v = lv
53 | )
54 | )
55 |
56 | result <- do.call(
57 | cpp_multirank_BIC_grid_search,
58 | public_arglist_w_penalty
59 | )
60 |
61 | result_directcall <- do.call(
62 | cpp_moma_multi_rank,
63 | public_arglist_w_penalty
64 | )
65 |
66 | if (sum(result_directcall$u) == 0) {
67 | zero_cnt <- zero_cnt + 1
68 | }
69 |
70 | expect_equal(result_directcall$u, get_5Dlist_elem(result, 1, 1, 1, 1)[[1]]$u$vector)
71 | expect_equal(result_directcall$v, get_5Dlist_elem(result, 1, 1, 1, 1)[[1]]$v$vector)
72 | }
73 | }
74 | }
75 | }
76 |
77 |
78 | # Make sure penalty levels spread evenly from
79 | # those that zeros everything to those that are
80 | # all zeros
81 | expect_lte(zero_cnt / (n_lambda_u * n_lambda_v * n_alpha_u * n_alpha_v), 0.1)
82 | })
83 |
84 | test_that("`cpp_multirank_BIC_grid_search`: a naive case", {
85 | arglist_x_w_penalty <- modifyList(
86 | public_arglist_wo_penalty,
87 | list(
88 | X = matrix(1),
89 | Omega_u = matrix(0),
90 | Omega_v = matrix(0),
91 | alpha_u = 0,
92 | alpha_v = 0,
93 | lambda_u = 0,
94 | lambda_v = 0
95 | )
96 | )
97 |
98 | result <- do.call(
99 | cpp_multirank_BIC_grid_search,
100 | arglist_x_w_penalty
101 | )[[1]]
102 |
103 | expect_equal(result$u$vector, as.matrix(1))
104 | expect_equal(result$v$vector, as.matrix(1))
105 | expect_equal(result$d, 1)
106 | })
107 |
--------------------------------------------------------------------------------
/tests/testthat/test_MGB_BIC.R:
--------------------------------------------------------------------------------
1 | context("`cpp_multirank_BIC_grid_search` as greedy BIC")
2 |
3 | set.seed(123)
4 | X <- matrix(runif(12), 3, 4) * 10
5 |
6 | # They are mutually prime. This is useful for testing
7 | # the size of the 5D list
8 | n_alpha_u <- 7
9 | n_alpha_v <- 5
10 | n_lambda_u <- 3
11 | n_lambda_v <- 2
12 | rank <- 3
13 |
14 | # Penalties should not be too high. Otherwise
15 | # u and v becomes vectors of zeros, and defaltion
16 | # is thus trivial.
17 | alpha_u <- seq(0, 3, length.out = n_alpha_u)
18 | alpha_v <- seq(0, 3, length.out = n_alpha_v)
19 | lambda_u <- seq(0, 3, length.out = n_lambda_u)
20 | lambda_v <- seq(0, 3, length.out = n_lambda_v)
21 |
22 | # public_arglist_wo_rank_and_selection does not specify two things: rank
23 | # and selection strategy for each parameter. They
24 | # are specified in each test case.
25 | public_arglist_wo_rank_and_selection <- c(
26 | list(
27 | X = X,
28 | alpha_u = alpha_u, alpha_v = alpha_v,
29 | Omega_u = second_diff_mat(3), Omega_v = second_diff_mat(4),
30 | lambda_u = lambda_u, lambda_v = lambda_v,
31 | prox_arg_list_u = add_default_prox_args(lasso()),
32 | prox_arg_list_v = add_default_prox_args(lasso())
33 | ),
34 | moma_pg_settings()
35 | )
36 |
37 | test_that("Returns correct vectors for chosen parameters", {
38 | result <- do.call(
39 | cpp_multirank_BIC_grid_search,
40 | c(
41 | public_arglist_wo_rank_and_selection,
42 | list(
43 | select_scheme_alpha_u = 0, # grid
44 | select_scheme_alpha_v = 0, # grid
45 | select_scheme_lambda_u = 1, # bic
46 | select_scheme_lambda_v = 1 # bic
47 | )
48 | )
49 | )
50 |
51 | # Loop order in C++ is (outmost) au, lu, av, lv (innermost)
52 | expect_equal(dim(result), c(7, 1, 5, 1, 1))
53 |
54 | for (i in 1:n_alpha_u) {
55 | for (j in 1:n_alpha_v) {
56 | res_i_j <- get_5Dlist_elem(result, i, 1, j, 1)[[1]]
57 | opt_alpha_u <- res_i_j$u$alpha
58 | opt_alpha_v <- res_i_j$v$alpha
59 | opt_lambda_u <- res_i_j$u$lambda
60 | opt_lambda_v <- res_i_j$v$lambda
61 |
62 | arglist_unary_penalty <- modifyList(
63 | public_arglist_wo_rank_and_selection,
64 | list(
65 | alpha_u = opt_alpha_u, alpha_v = opt_alpha_v,
66 | lambda_u = opt_lambda_u, lambda_v = opt_lambda_v
67 | )
68 | )
69 |
70 | result_directcall <- do.call(
71 | cpp_moma_multi_rank,
72 | arglist_unary_penalty
73 | )
74 |
75 | expect_equal(result_directcall$u, res_i_j$u$vector)
76 | expect_equal(result_directcall$v, res_i_j$v$vector)
77 | }
78 | }
79 | })
80 |
--------------------------------------------------------------------------------
/tests/testthat/test_MGB_multirank.R:
--------------------------------------------------------------------------------
1 | context("`cpp_multirank_BIC_grid_search` as multirank")
2 |
3 | set.seed(123)
4 | X <- matrix(runif(12), 3, 4) * 10
5 |
6 | # They are mutually prime. This is useful for testing
7 | # the size of the 5D list
8 | n_alpha_u <- 2
9 | n_alpha_v <- 3
10 | n_lambda_u <- 5
11 | n_lambda_v <- 7
12 |
13 | # Penalties should not be too high. Otherwise
14 | # u and v becomes vectors of zeros, and defaltion
15 | # is thus trivial.
16 | alpha_u <- seq(0, 1, length.out = n_alpha_u)
17 | alpha_v <- seq(0, 1, length.out = n_alpha_v)
18 | lambda_u <- seq(0, 1, length.out = n_lambda_u)
19 | lambda_v <- seq(0, 1, length.out = n_lambda_v)
20 |
21 | # public_arglist_wo_rank_and_selection does not specify two things: rank
22 | # and selection strategy for each parameter. They
23 | # are specified in each test case.
24 | public_arglist_wo_rank_and_selection <- c(
25 | list(
26 | X = X,
27 | alpha_u = alpha_u, alpha_v = alpha_v,
28 | Omega_u = second_diff_mat(3), Omega_v = second_diff_mat(4),
29 | lambda_u = lambda_u, lambda_v = lambda_v,
30 | prox_arg_list_u = add_default_prox_args(lasso()), prox_arg_list_v = add_default_prox_args(lasso())
31 | ),
32 | moma_pg_settings()
33 | )
34 |
35 | # Tests for multirank
36 | test_that("cpp_multirank_BIC_grid_search receives rank <= 0", {
37 | # case 1: rank=0
38 | arglist_w_rank <- c(
39 | public_arglist_wo_rank_and_selection,
40 | list(
41 | rank = 0
42 | )
43 | )
44 |
45 | expect_error(
46 | do.call(cpp_multirank_BIC_grid_search, arglist_w_rank),
47 | "rank in MoMA::grid_BIC_mix should >= 1"
48 | )
49 |
50 | # case 2: rank=-1
51 | arglist_w_rank$rank <- -1
52 | expect_error(
53 | do.call(cpp_multirank_BIC_grid_search, arglist_w_rank),
54 | "rank in MoMA::grid_BIC_mix should >= 1"
55 | )
56 | })
57 |
58 | test_that("cpp_multirank_BIC_grid_search returns multi-rank solution", {
59 | # four grid requests
60 | rank <- 3
61 |
62 | public_arglist_w_rank <-
63 | modifyList(
64 | public_arglist_wo_rank_and_selection,
65 | list(rank = rank)
66 | )
67 |
68 | result <- do.call(
69 | cpp_multirank_BIC_grid_search,
70 | public_arglist_w_rank
71 | )
72 |
73 | for (i in 1:n_alpha_u) {
74 | for (j in 1:n_alpha_v) {
75 | for (n in 1:n_lambda_u) {
76 | for (m in 1:n_lambda_v) {
77 | arglist_unary_penalty_wo_selection <-
78 | modifyList(
79 | public_arglist_wo_rank_and_selection,
80 | list(
81 | alpha_u = alpha_u[i],
82 | alpha_v = alpha_v[j],
83 | lambda_u = lambda_u[n],
84 | lambda_v = lambda_v[m],
85 | rank = rank
86 | )
87 | )
88 |
89 | # call cpp_moma_multi_rank
90 | result_directcall <- do.call(
91 | cpp_moma_multi_rank,
92 | arglist_unary_penalty_wo_selection
93 | )
94 |
95 | for (rank_i in 1:rank) {
96 | res <- get_5Dlist_elem(result, alpha_u_i = i, lambda_u_i = n, alpha_v_i = j, lambda_v_i = m, rank_i)[[1]]
97 | expect_equal(abs(matrix(result_directcall$u[, rank_i])), abs(res$u$vector))
98 | }
99 | }
100 | }
101 | }
102 | }
103 | })
104 |
--------------------------------------------------------------------------------
/tests/testthat/test_argument_extended.R:
--------------------------------------------------------------------------------
1 | context("Test extended argument helpers")
2 |
3 | test_that("moma_* works", {
4 | expect_true(all(
5 | moma_lasso()$sparsity_type$nonneg == FALSE,
6 | moma_lasso()$sparsity_type$P == "LASSO",
7 | moma_lasso()$sparsity_type$nonneg == FALSE,
8 | class(moma_lasso()) == "moma_sparsity_type",
9 | moma_lasso(non_negative = TRUE)$sparsity_type$nonneg == TRUE,
10 | all(c("lambda", "select_scheme", "non_negative") %in% names(formals(moma_lasso))),
11 | moma_lasso()$lambda == 0,
12 | moma_lasso()$select_scheme == "grid"
13 | ))
14 |
15 | expect_warning(
16 | moma_lasso(TRUE),
17 | "extra argument will be disregarded"
18 | )
19 |
20 |
21 | expect_true(all(
22 | moma_spfusedlasso(lambda2 = 2, lambda = seq(0, 10))$sparsity_type$lambda2 == 2,
23 | moma_spfusedlasso(lambda2 = 2, lambda = seq(0, 10))$lambda == seq(0, 10)
24 | ))
25 | })
26 |
--------------------------------------------------------------------------------
/tests/testthat/test_dof.R:
--------------------------------------------------------------------------------
1 | context("Test degree of freedom")
2 |
3 |
4 | test_that("DoF of fused lasso", {
5 | # constant
6 | x <- c(1, 1, 1, 1)
7 | expect_equal(1, test_df_orderedfusion(x))
8 |
9 | # fused group at the start
10 | x <- c(1, 1, 1, 2, 1)
11 | expect_equal(3, test_df_orderedfusion(x))
12 |
13 | # fused group at the end
14 | x <- c(1, 2, 1, 1, 1, 1)
15 | expect_equal(3, test_df_orderedfusion(x))
16 |
17 | # multiple fused groups
18 | x <- c(1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6)
19 | expect_equal(6, test_df_orderedfusion(x))
20 |
21 | # no fusion happens
22 | x <- seq(20)
23 | expect_equal(20, test_df_orderedfusion(x))
24 | })
25 |
26 | test_that("DoF of sparse fused lasso", {
27 | # constant
28 | x <- c(1, 1, 1, 1)
29 | expect_equal(1, test_df_spfusedlasso(x))
30 |
31 | # fused group at the beginning
32 | x <- c(1, 1, 1, 2, 1)
33 | expect_equal(3, test_df_spfusedlasso(x))
34 |
35 | # fused group at the end
36 | x <- c(1, 2, 1, 1, 1, 1)
37 | expect_equal(3, test_df_spfusedlasso(x))
38 |
39 | # multiple fused groups
40 | x <- c(1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6)
41 | expect_equal(6, test_df_spfusedlasso(x))
42 |
43 | # no fusion happens
44 | x <- seq(20)
45 | expect_equal(20, test_df_spfusedlasso(x))
46 |
47 | # zeros at the beginning
48 | x <- c(0, 0, 1, 2, 1, 1)
49 | expect_equal(3, test_df_spfusedlasso(x))
50 |
51 | # zeros in the middle
52 | x <- c(1, 0, 0, 2, 1, 1)
53 | expect_equal(3, test_df_spfusedlasso(x))
54 |
55 | # multiple groups of zeros in the middle
56 | x <- c(1, 0, 0, 2, 0, 0, 0, 3, 3, 0, 1, 1)
57 | expect_equal(4, test_df_spfusedlasso(x))
58 |
59 | # zeros in the end
60 | x <- c(1, 0, 0, 2, 1, 1, 0)
61 | expect_equal(3, test_df_spfusedlasso(x))
62 | })
63 |
64 |
65 | test_that("DoF of linear trend filtering", {
66 | x <- c(1, 1, 1, 1)
67 | expect_equal(2, test_df_l1gf(x, 1))
68 |
69 | # given any line (knot = 0) it should return DoF = 2
70 | x <- seq(0, 20, 0.3)
71 | for (rep in 1:10) {
72 | alpha <- runif(1)
73 | beta <- runif(1)
74 | xx <- alpha * x + beta
75 | expect_equal(2, test_df_l1gf(x, 1))
76 | }
77 |
78 | # one knot
79 | x <- seq(0, 20, 0.3)
80 | x <- 2 * abs(x - x[37]) - 2
81 | expect_equal(3, test_df_l1gf(x, 1))
82 |
83 | # three knots
84 | x <- seq(0, 20, 0.3)
85 | x <- 2 * abs(x - x[37]) - 2
86 | x <- 2 * abs(x - x[10]) - 2
87 | ## plot(x)
88 | expect_equal(5, test_df_l1gf(x, 1))
89 |
90 | # Find out knots using `diff``
91 | x <- runif(40)
92 | change_in_sec_diff <- sum(abs(diff(diff(x))) > 1e-10)
93 | expect_equal(change_in_sec_diff + 1 + 1, test_df_l1gf(x, 2))
94 | })
95 |
96 |
97 | test_that("DoF of quadratic trend filtering", {
98 |
99 | # constant
100 | x <- c(1, 1, 1, 1, 1)
101 | expect_equal(3, test_df_l1gf(x, 2))
102 |
103 | # given any line it should return DoF = 3
104 | x <- seq(0, 20, 0.3)
105 | for (rep in 1:10) {
106 | alpha <- runif(1)
107 | beta <- runif(1)
108 | xx <- alpha * x + beta
109 | expect_equal(3, test_df_l1gf(x, 2))
110 | }
111 |
112 | # given any quadratic curve it should return DoF = 3
113 | x <- seq(0, 20, 0.3)
114 | for (rep in 1:10) {
115 | alpha <- runif(1)
116 | beta <- runif(1)
117 | c <- runif(1)
118 | xx <- alpha * x^2 + beta * x + c
119 | expect_equal(3, test_df_l1gf(x, 2))
120 | }
121 |
122 | # Find out knots using `diff``
123 | change_in_sec_diff <- sum(abs(diff(diff(diff(x)))) > 1e-10)
124 |
125 | expect_equal(change_in_sec_diff + 2 + 1, test_df_l1gf(x, 2))
126 | })
127 |
--------------------------------------------------------------------------------
/tests/testthat/test_grid.R:
--------------------------------------------------------------------------------
1 | context("`cpp_moma_grid_search`` is equivalent to run `MoMA::solve` many times")
2 |
3 | test_that("Using cpp_moma_grid_search is equivalent to run MoMA::solve multiple times", {
4 | set.seed(332)
5 | n <- 7 # set n != p to avoid bugs
6 | p <- 11
7 | X <- matrix(runif(n * p), n)
8 |
9 | # generate p.d. matrices
10 | O_v <- crossprod(matrix(runif(p * p), p, p))
11 | O_u <- crossprod(matrix(runif(n * n), n, n))
12 |
13 | # run tests
14 | # NOTE: there's no need to test for large
15 | # lambda's and alpha's because in those
16 | # cases u and v are zeros
17 | sp_set <- seq(0, 3, 0.5)
18 | sm_set <- seq(0, 3, 0.5)
19 |
20 | # WARNING: cannot add scad or mcp here
21 | # I guess because they are non-convex, so
22 | # there is slight difference in the results
23 |
24 | # TODO: Add l1tf
25 | for (sptype in c(lasso, fusedlasso)) {
26 | ista.cv <- moma_svd(X,
27 | Omega_u = O_u, Omega_v = O_v, alpha_u = 0, alpha_v = sm_set,
28 | lambda_u = 0, lambda_v = sp_set, u_sparsity = lasso(), v_sparsity = sptype(),
29 | pg_settings = moma_pg_settings(EPS = 1e-14, MAX_ITER = 1e+5, solver = "ista", EPS_inner = 1e-9)
30 | )
31 | fista.cv <- moma_svd(X,
32 | Omega_u = O_u, Omega_v = O_v, alpha_u = 0, alpha_v = sm_set,
33 | lambda_u = 0, lambda_v = sp_set, u_sparsity = lasso(), v_sparsity = sptype(),
34 | pg_settings = moma_pg_settings(EPS = 1e-14, MAX_ITER = 1e+5, solver = "fista", EPS_inner = 1e-9)
35 | )
36 | cnt <- 1
37 | for (sp in sp_set) {
38 | for (sm in sm_set) {
39 | ista <- moma_svd(X,
40 | Omega_u = O_u, Omega_v = O_v, alpha_u = 0, alpha_v = sm,
41 | lambda_u = 0, lambda_v = sp, u_sparsity = lasso(), v_sparsity = sptype(),
42 | pg_settings = moma_pg_settings(EPS = 1e-14, MAX_ITER = 1e+5, solver = "ista", EPS_inner = 1e-9)
43 | )
44 | fista <- moma_svd(X,
45 | Omega_u = O_u, Omega_v = O_v, alpha_u = 0, alpha_v = sm,
46 | lambda_u = 0, lambda_v = sp, u_sparsity = lasso(), v_sparsity = sptype(),
47 | pg_settings = moma_pg_settings(EPS = 1e-14, MAX_ITER = 1e+5, solver = "fista", EPS_inner = 1e-9)
48 | )
49 |
50 | # Cannot use expect_equal here due to numerical error
51 | expect_lte(sum((ista$v[, 1] - ista.cv$v[, cnt])^2), 1e-7)
52 | expect_lte(sum((fista$v[, 1] - fista.cv$v[, cnt])^2), 1e-7)
53 | cnt <- cnt + 1
54 | }
55 | }
56 | }
57 | })
58 |
--------------------------------------------------------------------------------
/tests/testthat/test_logging.R:
--------------------------------------------------------------------------------
1 | library(stringr)
2 | context("Logging Tests")
3 |
4 | test_that("Logging controls work", {
5 | expect_error(moma_logger_level("BAD LEVEL"))
6 |
7 | moma_logger_level("INFO")
8 | expect_equal("INFO", moma_logger_level())
9 |
10 | moma_logger_level("MESSAGE")
11 | })
12 |
13 | test_that("INFO and DEBUG message print as expected", {
14 | moma_logger_level("MESSAGE")
15 |
16 | expect_silent(MoMA:::moma_info("A message"))
17 | expect_silent(MoMA:::moma_debug("A message"))
18 |
19 | moma_logger_level("DEBUG")
20 |
21 | expect_output(MoMA:::moma_info("A message"), "[INFO]")
22 | expect_output(MoMA:::moma_info("A message"), "A message")
23 |
24 | expect_output(MoMA:::moma_debug("The message"), "[DEBUG]")
25 | expect_output(MoMA:::moma_debug("The message"), "The message")
26 |
27 | moma_logger_level("MESSAGE")
28 | })
29 |
30 | test_that("Supressing messages works", {
31 | # At INFO level, everything is shown in R
32 | moma_logger_level("INFO")
33 |
34 | expect_error(MoMA:::moma_error("ERROR"))
35 | expect_warning(MoMA:::moma_warning("WARNING"))
36 | expect_message(MoMA:::moma_message("MESSAGE"))
37 |
38 | # At MESSAGE level, everything is shown in R
39 | moma_logger_level("MESSAGE")
40 |
41 | expect_error(MoMA:::moma_error("ERROR"))
42 | expect_warning(MoMA:::moma_warning("WARNING"))
43 | expect_message(MoMA:::moma_message("MESSAGE"))
44 |
45 | # At WARNING level, we don't get a message
46 | moma_logger_level("WARNING")
47 |
48 | expect_error(MoMA:::moma_error("ERROR"))
49 | expect_warning(MoMA:::moma_warning("WARNING"))
50 | expect_no_message(MoMA:::moma_message("MESSAGE"))
51 |
52 | # At ERROR level, we don't get a message or warning
53 | moma_logger_level("ERROR")
54 |
55 | expect_error(MoMA:::moma_error("ERROR"))
56 | expect_no_warning(MoMA:::moma_warning("WARNING"))
57 | expect_no_message(MoMA:::moma_message("MESSAGE"))
58 |
59 | moma_logger_level("MESSAGE")
60 | })
61 |
62 | test_that("No extra newlines", {
63 | moma_logger_level("DEBUG")
64 |
65 | e <- tryCatch(MoMA:::moma_error("MY ERROR"), error = identity)
66 | expect_equal(str_count(e$message, "\n"), 1)
67 |
68 | e <- tryCatch(MoMA:::moma_warning("MY WARNING"), warning = identity)
69 | expect_equal(str_count(e$message, "\n"), 1)
70 |
71 | e <- tryCatch(MoMA:::moma_message("MY MESSAGE"), message = identity)
72 | expect_equal(str_count(e$message, "\n"), 1)
73 |
74 | e <- tryCatch(MoMA:::moma_error("MY ERROR\nON TWO LINES"), error = identity)
75 | expect_equal(str_count(e$message, "\n"), 2)
76 |
77 | moma_logger_level("MESSAGE")
78 | })
79 |
80 | test_that("Function capture works at R level", {
81 | moma_logger_level("MESSAGE")
82 |
83 | f <- function(x) {
84 | MoMA:::moma_error("ERROR MESSAGE")
85 | }
86 |
87 | e <- tryCatch(f(), error = identity)
88 | expect_str_contains(e$message, "ERROR MESSAGE")
89 | expect_str_contains(e$message, "(Called from f)")
90 | expect_true(is.null(e$call))
91 | expect_true(is.null(e$cppstack))
92 |
93 | f <- function(x) {
94 | MoMA:::moma_error("ERROR MESSAGE", call = FALSE)
95 | }
96 | e <- tryCatch(f(), error = identity)
97 |
98 | expect_false(grepl("\\(Called from f\\)", e$message))
99 |
100 | f <- function(x) {
101 | MoMA:::moma_error("ERROR MESSAGE", call = "my func")
102 | }
103 | e <- tryCatch(f(), error = identity)
104 |
105 | expect_true(grepl("\\(Called from my func\\)", e$message))
106 |
107 | f <- function(x) {
108 | MoMA:::moma_warning("WARNING MESSAGE", call = FALSE)
109 | }
110 | e <- tryCatch(f(), warning = identity)
111 |
112 | expect_false(grepl("\\(Called from f\\)", e$message))
113 |
114 | f <- function(x) {
115 | MoMA:::moma_warning("WARNING MESSAGE", call = "my func")
116 | }
117 | e <- tryCatch(f(), warning = identity)
118 |
119 | expect_true(grepl("\\(Called from my func\\)", e$message))
120 | })
121 |
--------------------------------------------------------------------------------
/tests/testthat/test_prox_SLOPE.R:
--------------------------------------------------------------------------------
1 | context("SLOPE")
2 |
3 | proxSortedL1 <- function(x, l) {
4 |
5 | # Modification: Choose HB type lambda
6 | lambda <- vector(mode = "numeric", length = length(x))
7 |
8 | for (i in 1:length(x)) {
9 | lambda[i] <- qnorm(1 - i * 0.05 / 2 / length(x))
10 | }
11 |
12 | lambda <- lambda * l
13 |
14 | # Compare to the SLOPE package on CRAN
15 | result <- SLOPE::prox_sorted_L1(x, lambda, method = "c")
16 |
17 | return(result)
18 | }
19 |
20 | test_that("Compared to the SLOPE package", {
21 | if (requireNamespace("SLOPE")) {
22 | set.seed(123)
23 | reps <- 100
24 | for (i in 1:reps) {
25 | x <- runif(10)
26 | for (lambda in seq(0, 3, 0.2)) {
27 | expect_equal(
28 | test_prox_slope(x, lambda),
29 | as.matrix(proxSortedL1(x, lambda))
30 | )
31 | }
32 | }
33 | }
34 | })
35 |
--------------------------------------------------------------------------------
/tests/testthat/test_prox_fused_lasso.R:
--------------------------------------------------------------------------------
1 | context("Ordered Fused lasso tests")
2 |
3 | test_that("A numeric example: Ordered fused lasso should return correct values under different lambdas", {
4 | set.seed(34)
5 | x <- 10 * runif(10)
6 | # result generated by flsa
7 | # These lambdas are the knots where merges happen.
8 |
9 | # library(flsa)
10 | # flsa::flsaTopDown(x)
11 | goal <- matrix(c(
12 | 4.447685, 5.447685, 6.447685, 6.760676, 6.427343, 6.094010, 5.760676, 5.612593, 5.612593, 5.612593, 5.612593,
13 | 9.985404, 8.417172, 7.417172, 6.760676, 6.427343, 6.094010, 5.760676, 5.612593, 5.612593, 5.612593, 5.612593,
14 | 8.848940, 8.417172, 7.417172, 6.760676, 6.427343, 6.094010, 5.760676, 5.612593, 5.612593, 5.612593, 5.612593,
15 | 2.384260, 3.328699, 4.328699, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593,
16 | 2.273138, 3.328699, 4.328699, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593,
17 | 8.477694, 6.477694, 5.237301, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593,
18 | 2.825617, 4.825617, 5.237301, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593,
19 | 7.176086, 5.294398, 5.237301, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593,
20 | 3.960512, 5.294398, 5.237301, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593,
21 | 5.746595, 5.294398, 5.237301, 5.120557, 5.263415, 5.406272, 5.549129, 5.612593, 5.612593, 5.612593, 5.612593
22 | ),
23 | nrow = 10,
24 | byrow = T
25 | )
26 | lambdas <- seq(0, 10, 1)
27 | for (l in 1:10) {
28 | expect_lte(norm(test_prox_fusedlassopath(x, lambdas[l]) - matrix(goal[, l], nrow = 10)), 1e-5)
29 | }
30 | })
31 |
32 | test_that("Equals to mean when lambda is large enough", {
33 | l <- 1e+100
34 | set.seed(34)
35 | for (i in 1000) {
36 | x <- 10 * runif(10)
37 | proxed.x <- test_prox_fusedlassopath(x, l)
38 | for (i in 1:9) {
39 | expect_equal(proxed.x[i], proxed.x[i + 1])
40 | }
41 | expect_equal(mean(x), proxed.x[1])
42 | }
43 | })
44 |
45 | test_that("Same results as the `flsa` package", {
46 | set.seed(43)
47 | if (requireNamespace("flsa")) {
48 | library(flsa)
49 |
50 | # Problem size ranging from 2 to 200
51 | for (p in seq(2, 200, 10)) {
52 | # Repeat 10 times
53 | for (i in 1:10) {
54 | x <- 10 * runif(p)
55 | # Penalty levels
56 | for (lambda in seq(0, 5, 0.5)) {
57 | expect_equal(
58 | test_prox_fusedlassopath(x, lambda),
59 | t(flsa::flsaGetSolution(flsa::flsa(x), lambda2 = lambda))
60 | )
61 | }
62 | }
63 | }
64 | }
65 | })
66 |
67 | test_that("DP approach should give the same results as the `flsa` package", {
68 | set.seed(43)
69 | if (requireNamespace("flsa")) {
70 | library(flsa)
71 |
72 | # Problem size ranging from 2 to 200
73 | for (p in seq(2, 200, 10)) {
74 | # Repeat 10 times
75 | for (i in 1:10) {
76 | x <- 10 * runif(p)
77 | # Penalty levels
78 | for (lambda in seq(0, 5, 0.5)) {
79 | expect_equal(
80 | test_prox_fusedlassodp(x, lambda),
81 | t(flsa::flsaGetSolution(flsa::flsa(x), lambda2 = lambda))
82 | )
83 | if (lambda == 5) {
84 | # make sure we test the entire path
85 | expect(sum(abs(test_prox_fusedlassodp(x, lambda))), 0)
86 | }
87 | }
88 | }
89 | }
90 | }
91 | })
92 |
93 | test_that("Test DP approach buffer size", {
94 | set.seed(43)
95 | if (requireNamespace("flsa")) {
96 | library(flsa)
97 | lambda <- 1
98 | # Problem size
99 | for (p in c(10000000)) {
100 | # Repeat 10 times
101 | for (i in 1:10) {
102 | x <- 10 * runif(p)
103 | # Path algorithm takes 10 seconds to solve each.
104 | # DP takes 0.5 seconds.
105 | expect_equal(
106 | test_prox_fusedlassodp(x, lambda),
107 | test_prox_fusedlassopath(x, lambda)
108 | )
109 | }
110 | }
111 | }
112 | })
113 |
--------------------------------------------------------------------------------
/tests/testthat/test_prox_sparse_fused_lasso.R:
--------------------------------------------------------------------------------
1 | context("Sparse fused lasso tests")
2 |
3 | test_that("Same results as the `flsa` package", {
4 | set.seed(43)
5 | if (requireNamespace("flsa")) {
6 | library(flsa)
7 | pset <- seq(2, 8)
8 | for (p in pset) {
9 | for (i in 1:20) {
10 | x <- 10 * runif(p)
11 | for (lambda in seq(0, 2, 0.1)) {
12 | for (lambda2 in seq(0, 2, 0.2)) {
13 | expect_equal(
14 | test_prox_spfusedlasso(x, lambda, lambda2 = lambda2),
15 | matrix(flsaGetSolution(flsa(x), lambda2 = lambda, lambda1 = lambda2))
16 | )
17 | }
18 | }
19 | }
20 | }
21 | }
22 | })
23 |
--------------------------------------------------------------------------------
/tests/testthat/test_prox_unordered_fusion.R:
--------------------------------------------------------------------------------
1 | context("Unordered Fusion Lasso Tests")
2 |
3 | # Special case 1:
4 | # Large lambda: lambdas in each group are
5 | # the means of everything in the group
6 | test_that("Find means of everything when lambda is large enough and the graph is fully connected", {
7 | set.seed(43)
8 | rep <- 10
9 | large.lambda <- 10000
10 | for (p in c(5, 30, 40, 100)) {
11 | y <- runif(p)
12 |
13 | # A fully connected graph with random weights
14 | w <- matrix(rep(0, p * p), p, byrow = T)
15 | for (i in 1:p - 1) {
16 | for (j in (i + 1):p) {
17 | w[i, j] <- runif(1) + 1
18 | }
19 | }
20 |
21 | for (i in 1:rep) {
22 | res.AMA <- test_prox_fusion(y, large.lambda, w, ADMM = FALSE, acc = FALSE)
23 | res.AMA.acc <- test_prox_fusion(y, large.lambda, w, ADMM = FALSE, acc = TRUE)
24 | res.ADMM <- test_prox_fusion(y, large.lambda, w, ADMM = TRUE, acc = FALSE)
25 | for (j in c(
26 | res.AMA,
27 | res.AMA.acc,
28 | res.ADMM
29 | )) {
30 | expect_equal(j, mean(y))
31 | }
32 | }
33 | }
34 | })
35 |
36 | test_that("Find means of connected components when lambda is large enough", {
37 | set.seed(33)
38 | rep <- 10
39 | large.lambda <- 1000
40 | for (p in c(9, 99)) {
41 |
42 | # A weight matrix of 3 connected components
43 | w <- matrix(rep(0, p * p), p, byrow = T)
44 | num.comp.nodes <- p / 3 # the number of nodes in each component
45 | for (i in seq(1, p, num.comp.nodes)) {
46 | w[i, (i + 1):(i + num.comp.nodes - 1)] <- 1 + runif(num.comp.nodes - 1)
47 | }
48 |
49 | for (j in 1:rep) {
50 | y <- 10 * runif(p)
51 | res.AMA.unacc <- test_prox_fusion(y, large.lambda, w, ADMM = FALSE, acc = TRUE)
52 | res.AMA.acc <- test_prox_fusion(y, large.lambda, w, ADMM = FALSE, acc = TRUE)
53 | res.ADMM <- test_prox_fusion(y, large.lambda, w, ADMM = TRUE, acc = FALSE)
54 | for (res in list(
55 | res.AMA.unacc,
56 | res.AMA.acc,
57 | res.ADMM
58 | )) {
59 | for (i in 1:p) {
60 | start <- ((i - 1) %/% num.comp.nodes) * num.comp.nodes + 1
61 | end <- start + num.comp.nodes - 1
62 | expect_lte(abs(res[i] - mean(y[start:end])), 1e-6)
63 | }
64 | }
65 | }
66 | }
67 | })
68 |
69 | # Special case 2:
70 | # For every lambda: when only w_ij = 1 (j = i+1)
71 | # it becomes ordered fused lasso
72 | test_that("Ordered fused lasso when w_ij = 1 all j = i+1", {
73 | set.seed(44)
74 | rep <- 20
75 | for (p in c(3, 20, 100)) {
76 |
77 | # A chained graph
78 | w <- matrix(rep(0, p * p), p, byrow = T)
79 | for (i in 1:(p - 1)) {
80 | w[i, i + 1] <- 1
81 | }
82 |
83 | for (i in 1:rep) {
84 | y <- 10 * runif(p)
85 | err.AMA.unacc <- norm(test_prox_fusedlassodp(y, 1) - test_prox_fusion(y, 1, w, ADMM = FALSE, acc = TRUE))
86 | err.AMA.acc <- norm(test_prox_fusedlassodp(y, 1) - test_prox_fusion(y, 1, w, ADMM = FALSE, acc = TRUE))
87 | err.ADMM <- norm(test_prox_fusedlassodp(y, 1) - test_prox_fusion(y, 1, w, ADMM = TRUE, acc = FALSE))
88 | for (err in c(
89 | err.AMA.unacc,
90 | err.AMA.acc,
91 | err.ADMM
92 | )) {
93 | expect_lte(err, 1e-4)
94 | }
95 | }
96 | }
97 | })
98 |
99 | # Special case 3:
100 | # For evry lambda: when all i,j w_ij = 1
101 | # the solution path contains no split.
102 |
103 | # Find the weight vector required by the
104 | # `cvxclustr` package
105 | mat_to_vec <- function(my.w, p) {
106 | cnt <- 1
107 | cvx.w <- vector(mode = "numeric", length = p * (p - 1) / 2)
108 | for (jj in 1:(p - 1)) {
109 | for (ii in (jj + 1):p) {
110 | cvx.w[cnt] <- my.w[jj, ii]
111 | cnt <- cnt + 1
112 | }
113 | }
114 | return(cvx.w)
115 | }
116 |
117 | test_that("Unweighted and fully connected graph, i.e., w_ij = 1 for all i, j", {
118 | if (requireNamespace("cvxclustr")) {
119 | set.seed(33)
120 | rep <- 20
121 |
122 | for (p in c(30, 100)) {
123 |
124 | # A weight matrix where w_ij = 1, all i, j
125 | w <- matrix(rep(1, p * p), p, byrow = T)
126 | for (i in 1:(p - 1)) {
127 | for (j in (i + 1):p) {
128 | w[i, j] <- runif(1) + 1
129 | }
130 | }
131 |
132 | for (i in 1:rep) {
133 | y <- 10 * runif(p)
134 | y <- t(matrix(y))
135 |
136 | # The cvxclustr package stores weights as a vector.
137 | # For Gaussian kernel, wij = exp(-phi ||X[,i]-X[,j]||^2)
138 | # So phi = 0 makes a fully connected and unweighted graph
139 | for (lambda in seq(0, 1, 0.13)) {
140 | cvx.result <- cvxclustr::cvxclust(y, mat_to_vec(w, p), lambda, method = "admm", tol = 1e-10)$U[[1]]
141 |
142 | admm <- t(matrix(test_prox_fusion(y, lambda, w, ADMM = TRUE, acc = FALSE)))
143 | ama <- t(matrix(test_prox_fusion(y, lambda, w, ADMM = FALSE, acc = FALSE)))
144 | ama.acc <- t(matrix(test_prox_fusion(y, lambda, w, ADMM = FALSE, acc = TRUE)))
145 | }
146 |
147 | err.AMA.unacc <- norm(cvx.result - ama)
148 | err.AMA.acc <- norm(cvx.result - ama.acc)
149 | err.ADMM <- norm(cvx.result - admm)
150 | for (err in c(
151 | err.AMA.unacc,
152 | err.AMA.acc,
153 | err.ADMM
154 | )) {
155 | expect_lte(err, 1e-6)
156 | }
157 | }
158 | }
159 | }
160 | })
161 |
--------------------------------------------------------------------------------
/tests/testthat/test_solve.R:
--------------------------------------------------------------------------------
1 | context("SFPCA tests")
2 | test_that("Equivalent to SVD when no penalty imposed", {
3 | set.seed(32)
4 |
5 | for (i in 1:30) {
6 | n <- 17 # set n != p to test bugs
7 | p <- 23
8 | X <- matrix(runif(n * p), n)
9 | sfpca <- sfpca(X)
10 |
11 | svd.result <- svd(X)
12 | svd.result$u[, 1:4]
13 | sfpca$u
14 |
15 | expect_equal(norm(svd.result$v[, 1] - sfpca$v), 0)
16 | expect_equal(norm(svd.result$u[, 1] - sfpca$u), 0)
17 | expect_equal(svd.result$d[1], sfpca$d[1])
18 | }
19 | })
20 |
21 | test_that("Closed-form solution when Omega = I and no sparsity", {
22 | set.seed(32)
23 | n <- 17 # set n != p to test bugs
24 | p <- 23
25 | a_u.range <- seq(0, 3, 0.05)
26 | a_v.range <- seq(0, 3, 0.05)
27 | for (a_u in a_u.range) {
28 | for (a_v in a_v.range) {
29 | for (solver in c("ISTA", "FISTA", "ONESTEPISTA")) {
30 | # NOTE: We can have one-step ISTA here
31 | X <- matrix(runif(n * p), n)
32 |
33 | sfpca <- sfpca(X,
34 | alpha_u = a_u, alpha_v = a_v, Omega_u = diag(n), Omega_v = diag(p),
35 | EPS = 1e-9, MAX_ITER = 1e+5, solver = solver
36 | )
37 | svd.result <- svd(X)
38 | expect_equal(norm(svd.result$v[, 1] - sqrt(1 + a_v) * sfpca$v), 0)
39 | expect_equal(norm(svd.result$u[, 1] - sqrt(1 + a_u) * sfpca$u), 0)
40 | expect_equal(svd.result$d[1], sqrt((1 + a_v) * (1 + a_u)) * sfpca$d[1])
41 | }
42 | }
43 | }
44 | })
45 |
46 | test_that("Closed-form solution when no sparsity imposed", {
47 | n <- 17 # set n != p to test bugs
48 | p <- 23
49 | set.seed(32)
50 | X <- matrix(runif(n * p), n)
51 |
52 | # construct p.d. matrix as smoothing matrix
53 | O_v <- crossprod(matrix(runif(p * p), p, p))
54 | O_u <- crossprod(matrix(runif(n * n), n, n))
55 |
56 | # set some random alpha's
57 | # WARNING: running time increases quickly as alpha increases
58 | a_u.range <- seq(5)
59 | a_v.range <- seq(5)
60 | for (a_u in a_u.range) {
61 | for (a_v in a_v.range) {
62 | # Cholesky decomposition, note S = I + alpah * Omega
63 | Lv <- chol(a_v * O_v + diag(p))
64 | Lu <- chol(a_u * O_u + diag(n))
65 |
66 | svd.result <- svd(t(solve(Lu)) %*% X %*% solve(Lv))
67 | svd.result.v <- svd.result$v[, 1]
68 | svd.result.u <- svd.result$u[, 1]
69 |
70 | for (solver in c("ISTA", "FISTA")) {
71 | # WARNING: One-step ISTA does not pass this test
72 | res <- sfpca(X,
73 | Omega_u = O_u, Omega_v = O_v, alpha_u = a_u, alpha_v = a_v,
74 | EPS = 1e-7, MAX_ITER = 1e+5, solver = solver
75 | )
76 |
77 | # The sfpca solutions and the svd solutions are related by an `L` matrix
78 | res.v <- Lv %*% res$v
79 | res.u <- Lu %*% res$u
80 |
81 | # same.direction = 1 if same direction else -1
82 | same.direction <- ((svd.result$v[, 1][1] * res.v[1]) > 0) * 2 - 1
83 |
84 | # tests
85 | expect_lte(norm(svd.result$v[, 1] - same.direction * res.v), 1e-5)
86 | expect_lte(norm(svd.result$u[, 1] - same.direction * res.u), 1e-5)
87 | }
88 | }
89 | }
90 | })
91 |
92 | test_that("ISTA and FISTA should yield similar results,
93 | in the presence of both sparse and smooth penalty", {
94 | set.seed(332)
95 | n <- 7 # set n != p to test bugs
96 | p <- 11
97 | X <- matrix(runif(n * p), n)
98 |
99 | # generate p.d. matrices
100 | O_v <- crossprod(matrix(runif(p * p), p, p))
101 | O_u <- crossprod(matrix(runif(n * n), n, n))
102 |
103 | # run tests
104 | # NOTE: there's no need to test for large
105 | # lambda's and alpha's because in those
106 | # cases u and v are zeros
107 | cnt <- 0
108 | for (sp in seq(0, 5, 0.1)) {
109 | for (sm in seq(0, 5, 0.1)) {
110 | # TODO: Add "L1TRENDFILTERING"
111 | for (sptype in c("LASSO", "SCAD", "MCP", "ORDEREDFUSED")) {
112 | ista <- sfpca(X,
113 | Omega_u = O_u, Omega_v = O_v, alpha_u = sp, alpha_v = sp,
114 | lambda_u = sm, lambda_v = sm, P_u = "LASSO", P_v = sptype,
115 | EPS = 1e-14, MAX_ITER = 1e+3, solver = "ISTA", EPS_inner = 1e-9
116 | )
117 | fista <- sfpca(X,
118 | Omega_u = O_u, Omega_v = O_v, alpha_u = sp, alpha_v = sp,
119 | lambda_u = sm, lambda_v = sm, P_u = "LASSO", P_v = sptype,
120 | EPS = 1e-6, MAX_ITER = 1e+3, solver = "FISTA", EPS_inner = 1e-9
121 | )
122 |
123 | # WARNING: We observe if zero appears in either v or u, ista and fista
124 | # might not give identical results.
125 | # Maybe they will both eventually go to the same point, but ista slows
126 | # down a lot before it reaches it and consequently meets the stopping criterion.
127 | if (sum(ista$v[, 1] == 0.0) == 0
128 | && sum(fista$v[, 1] == 0.0) == 0) {
129 | expect_lte(sum((ista$v[, 1] - fista$v[, 1])^2), 1e-6)
130 | expect_lte(sum((ista$u[, 1] - fista$u[, 1])^2), 1e-6)
131 | }
132 | }
133 | }
134 | }
135 | })
136 |
--------------------------------------------------------------------------------
/tests/testthat/test_util.R:
--------------------------------------------------------------------------------
1 | context("Tests for Util.R")
2 |
3 | test_that("is_* functions", {
4 | expect_true(all(
5 | is_finite_numeric_scalar(1),
6 | !is_finite_numeric_scalar(c()),
7 | is_finite_numeric_scalar(c(1)),
8 | !is_finite_numeric_scalar("a"),
9 | !is_finite_numeric_scalar(Inf),
10 | !is_finite_numeric_scalar(NaN),
11 | !is_finite_numeric_scalar(NA)
12 | ))
13 |
14 | expect_true(all(
15 | # compatible with `is_finite_numeric_scalar`
16 | is_valid_parameters(1),
17 | !is_valid_parameters(c()),
18 | is_valid_parameters(c(1)),
19 | !is_valid_parameters("a"),
20 | !is_valid_parameters(Inf),
21 | !is_valid_parameters(NaN),
22 | !is_valid_parameters(NA),
23 |
24 | !is_valid_parameters(list()),
25 | !is_valid_parameters(c("a", 1)),
26 | !is_valid_parameters(list(1, list(1, 2, 3))),
27 |
28 | !is_valid_parameters(c(1, Inf)),
29 | !is_valid_parameters(c(Inf, 1)),
30 | !is_valid_parameters(c(1, NA)),
31 | !is_valid_parameters(c(NA)),
32 | !is_valid_parameters(c(1, NaN)),
33 | !is_valid_parameters(c(NaN, 1)),
34 |
35 | is_valid_parameters(seq(0, 10)),
36 | is_valid_parameters(matrix(c(1, 2, 3, 4), 2)),
37 | is_valid_parameters(c(1, 2, 3)),
38 | is_valid_parameters(list(1, 2, 3))
39 | ))
40 |
41 |
42 | expect_true(all(
43 | !is_valid_select_str(1),
44 | !is_valid_select_str("a"),
45 | is_valid_select_str("g"),
46 | is_valid_select_str("b"),
47 | !is_valid_select_str("bb"),
48 | !is_valid_select_str("")
49 | ))
50 | })
51 |
--------------------------------------------------------------------------------
/vignettes/moma-LDA.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Linear Discriminant Analysis with MoMA"
3 | author: "Luofeng Liao"
4 | date: "`r Sys.Date()`"
5 | output: html_vignette
6 | bibliography: vignettes.bibtex
7 | vignette: >
8 | %\VignetteIndexEntry{Linear Discriminant Analysis with MoMA}
9 | %\VignetteEngine{knitr::rmarkdown}
10 | %\VignetteEncoding{UTF-8}
11 | ---
12 |
13 | ```{r echo=FALSE,cache=FALSE}
14 | set.seed(1234)
15 | knitr::opts_chunk$set(cache = TRUE)
16 | ```
17 |
18 | ## The `iris` Data Set
19 |
20 | Citing the R package `datasets`, "this famous (Fisher's or Anderson's) iris data set gives the measurements in centimeters of the variables sepal length and width and petal length and width, respectively, for 50 flowers from each of 3 species of iris. The species are Iris setosa, versicolor, and virginica."
21 |
22 | There are four features in the data set: `Sepal.Length`, `Sepal.Width`, `Petal.Length`, `Petal.Width`.
23 |
24 | ```{r eval = FALSE}
25 | library(MoMA)
26 |
27 | ## collect data
28 | X <- iris[, 1:4]
29 | grouping <- as.factor(rep(c("s", "c", "v"), rep(50, 3)))
30 |
31 | ## range of penalty
32 | lambda <- seq(0, 1, 0.1)
33 |
34 | ## run!
35 | a <- moma_sflda(
36 | X = X,
37 | Y_factor = grouping,
38 | x_sparse = moma_lasso(lambda = lambda),
39 | rank = 3
40 | )
41 |
42 | plot(a) # start a Shiny app and play with it!
43 | ```
44 |
45 |
--------------------------------------------------------------------------------
/vignettes/moma-PCA.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Principal Component Analysis with MoMA"
3 | author: "Luofeng Liao"
4 | date: "`r Sys.Date()`"
5 | output: html_vignette
6 | bibliography: vignettes.bibtex
7 | vignette: >
8 | %\VignetteIndexEntry{Principal Component Analysis with MoMA}
9 | %\VignetteEngine{knitr::rmarkdown}
10 | %\VignetteEncoding{UTF-8}
11 | ---
12 |
13 | ```{r echo=FALSE,cache=FALSE}
14 | set.seed(1234)
15 | knitr::opts_chunk$set(cache = TRUE)
16 | ```
17 |
18 | ## The `mtcar` Data Set
19 |
20 | Citing the R documentation of the `mtcar` (Motor Trend Car Road Tests) data set, "the data was extracted from the 1974 Motor Trend US magazine, and comprises fuel consumption and 10 aspects of automobile design and performance for 32 automobiles (1973–74 models)".
21 |
22 | The data format is as follows.
23 |
24 | ```
25 | [, 1] mpg: Miles/(US) gallon
26 | [, 2] cyl: Number of cylinders
27 | [, 3] disp: Displacement (cu.in.)
28 | [, 4] hp: Gross horsepower
29 | [, 5] drat: Rear axle ratio
30 | [, 6] wt: Weight (1000 lbs)
31 | [, 7] qsec: 1/4 mile time
32 | [, 8] vs: Engine (0 = V-shaped, 1 = straight)
33 | [, 9] am: Transmission (0 = automatic, 1 = manual)
34 | [,10] gear: Number of forward gears
35 | [,11] carb: Number of carburetors
36 | ```
37 |
38 | Suppose we are interested in creating new "features" that
39 |
40 | * are linear combinations of known features,
41 |
42 | * cpature as much information as possible, and
43 |
44 | * comprise of only some of the known features.
45 |
46 | Then we can use the `moma_spca()` function (Sparse Principal Component Analysis).
47 |
48 | ```{r message=FALSE}
49 | library(MoMA)
50 |
51 | # Get rid of two categorical variables:
52 | # X[, 8]: Engine (0 = V-shaped, 1 = straight)
53 | # X[, 9]: Transmission (0 = automatic, 1 = manual
54 | X <- as.matrix(datasets::mtcars[, c(1:7, 10, 11)])
55 | lambda_len <- 30
56 |
57 | a <- moma_spca(X,
58 | center = TRUE, scale = TRUE,
59 | v_sparse = moma_lasso(
60 | lambda = seq(0, 5, length.out = lambda_len)
61 | ),
62 | rank = 2
63 | )
64 | ```
65 |
66 |
67 | ## Access the Results
68 |
69 | #### Get the loadings by `get_mat_by_index()$V`.
70 | ```{r}
71 | ld_10 <- a$get_mat_by_index(lambda_v = 10)
72 |
73 | cat("chosen lambda for the first PC = ", ld_10$chosen_lambda_v[1], "\n")
74 | cat("chosen lambda for the second PC = ", ld_10$chosen_lambda_v[2], "\n")
75 | print(ld_10$V)
76 | ```
77 |
78 | #### Project New Data
79 |
80 | Project new data onto the space spanned by new principal components.
81 |
82 | ```{r}
83 | # Let's pretend the first ten rows of `mtcars` are new data
84 | newX <- X[1:10, ]
85 |
86 | # `rank = 2`: the dimension of projected space
87 | # `lambda_v`: an integer, the penalty level
88 | a$left_project(newX = newX, rank = 2, lambda_v = 5)$proj_data
89 | ```
90 |
91 | #### Start a Shiny App
92 |
93 | Start a Shiny App and see how penalty levels affect loadings and the 2-D projection of original data.
94 |
95 | ```{r eval = FALSE}
96 | plot(a)
97 | ```
98 |
99 |
--------------------------------------------------------------------------------
/vignettes/moma-quick-start.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Introduction to the `MoMA` Package"
3 | author: "Michael Weylandt, Luofeng Liao"
4 | date: "`r Sys.Date()`"
5 | output: html_vignette
6 | bibliography: vignettes.bibtex
7 | vignette: >
8 | %\VignetteIndexEntry{MoMA}
9 | %\VignetteEngine{knitr::rmarkdown}
10 | %\VignetteEncoding{UTF-8}
11 | ---
12 |
13 | ```{r echo=FALSE,cache=FALSE}
14 | set.seed(1234)
15 | knitr::opts_chunk$set(cache = TRUE, collapse = TRUE)
16 | ```
17 |
18 | The unified SFPCA (Sparse and Functional Principal Component Analysis) method enjoys many advantages over existing approaches to regularized PC, because it
19 |
20 | * allows for arbitrary degrees and forms of regularization;
21 |
22 | * unifies many existing methods;
23 |
24 | * admits a tractable, efficient, and theoretically well-grounded algorithm.
25 |
26 | The problem is formulated as follows.
27 |
28 | $$\max_{u,\,,v}{u}^{T} {X} {v}-\lambda_{{u}} P_{{u}}({u})-\lambda_{{v}} P_{{v}}({v})$$
29 | $$\text{s.t. } \| u \| _ {S_u} \leq 1, \, \| v \| _ {S_v} \leq 1.$$
30 | Typically, we take ${S}_{{u}}={I}+\alpha_{{u}} {\Omega}_{{u}}$ where $\Omega_u$ is the second- or fourth-difference matrix, so that the $\|u \|_{S_u}$ penalty term encourages smoothness in the estimated singular vectors. $P_u$ and $P_v$ are sparsity inducing penalties that satisfy the following conditions:
31 |
32 | * $P \geq 0$, $P$ defined on $[0,+\infty)$;
33 |
34 | * $P(cx) = c P (x), \forall \, c > 0$.
35 |
36 | ## A Wide Range of Modeling Options
37 |
38 | Currently, the package supports arbitrary combination of the following.
39 |
40 | #### Various sparsity-inducing penalties
41 |
42 | So far, we have incorporated the following penalties in MoMA. The code under each penalty is only an example specification of the penalty. They should be carefully tailored based on your particular data set.
43 |
44 | * LASSO (least absolute shrinkage and selection operator), see `moma_lasso`;
45 | ``` {r eval = FALSE}
46 | # `non_negative`: impose non-negativity constraint or not
47 | moma_lasso(non_negative = TURE)
48 | ```
49 |
50 | * SCAD `moma_lasso`(smoothly clipped absolute deviation), see `moma_scad`;
51 | ``` {r eval = FALSE}
52 | # `gamma` is the non-convexity parameter
53 | moma_scad(gamma = 3, non_negative = TURE)
54 | ```
55 |
56 | * MCP (minimax concave penalty), see `moma_mcp`;
57 | ``` {r eval = FALSE}
58 | # `gamma` is the non-convexity parameter
59 | moma_mcp(gamma = 3, non_negative = TURE)
60 | ```
61 |
62 | * SLOPE (sorted $\ell$-one penalized estimation), see `moma_slope`;
63 | ``` {r eval = FALSE}
64 | # `gamma` is the non-convexity parameter
65 | moma_slope(gamma = 3, non_negative = TURE)
66 | ```
67 |
68 | * Group LASSO, see `moma_grplasso`;
69 | ``` {r eval = FALSE}
70 | # `g` is a factor indicating the grouping
71 | moma_grplasso(g = g, non_negative = TURE)
72 | ```
73 |
74 | * Fused LASSO, see `moma_fusedlasso`;
75 | ``` {r eval = FALSE}
76 | # `algo` is indicates which algorithm to solve the proximal operator
77 | # "dp": dynamic programming, "path": path-based algorithm
78 | moma_fusedlasso(algo = "dp")
79 | ```
80 |
81 | * L1 trend filtering, see `moma_l1tf`;
82 | ``` {r eval = FALSE}
83 | # `l1tf_k = 2` imposes piece-wise linear
84 | moma_l1tf(l1tf_k = 2)
85 | ```
86 |
87 | * Sparse fused LASSO, see `moma_spfusedlasso`;
88 | ``` {r eval = FALSE}
89 | # `lambda2` is penalty level for the adjacent difference
90 | moma_spfusedlasso(lambda2 = 1)
91 | ```
92 |
93 | * Cluster penalty, see `moma_cluster`.
94 | ``` {r eval = FALSE}
95 | # `w` is a symmectric matrix, whose entry, w[i][j], is the weight connecting
96 | # the i-th and the j-th element
97 | moma_cluster(w = w)
98 | ```
99 |
100 | #### Parameter selection schemes
101 |
102 | * Exhaustive search
103 |
104 | * Nested BIC. See `select_scheme` for details.
105 |
106 | #### Multivariate methods
107 |
108 | * PCA (Principal Component Analysis). See `moma_sfpca`.
109 |
110 | * CCA (Canonical Component Analysis). See `moma_sfcca`.
111 |
112 | * LDA (Linear Discriminant Anlsysis). See `moma_sflda`.
113 |
114 | * PLS (Partial Least Square) (TODO)
115 |
116 | * Correspondence Analysis (TODO)
117 |
118 | #### Deflation schemes
119 |
120 | * Hotelling's deflation (PCA)
121 |
122 | * Projection deflation (PCA, CCA, LDA)
123 |
124 | * Schur's complement (PCA)
125 |
126 | ## Excellent User Experience
127 |
128 | * Easy-to-use functions. Let $\Delta$ be a second-difference matrix of appropriate size, such that $u^T\Delta u = \sum_i (u_{i} - u_{i-1} )^2$. For a matrix $X$, one line of code can solve the following penalized singular value decomposition problem:
129 |
130 | $$\max_{u,\, v} \, {u}^{T} {X} {v} - 4 \sum_i | v_i - v_{i-1}|$$
131 | $$ \text{s.t. } u^T(I + 3 \Delta) u \leq 1,\, v^Tv \leq 1.$$
132 |
133 | ```{r eval=FALSE}
134 | # `p` is the length of `u`
135 | moma_sfpca(X,
136 | center = FALSE,
137 | v_sparse = moma_fusedlasso(lambda = 4),
138 | u_smooth = moma_smoothness(second_diff_mat(p), alpha = 3)
139 | )
140 | ```
141 |
142 |
143 | * R6 methods to support access of results.
144 |
145 | * Shiny supports interation with MoMA.
146 |
147 | * Fast. `MoMA` uses the `Rcpp` and `RcppArmadillo` libraries for speed
148 | [@Eddelbuettel:2011; @Eddelbuettel:2014; @Sanderson:2016].
149 |
150 | ## References
151 |
152 |
--------------------------------------------------------------------------------
/vignettes/vignettes.bibtex:
--------------------------------------------------------------------------------
1 | @ARTICLE{Eddelbuettel:2014,
2 | TITLE="\texttt{RcppArmadillo}: Accelerating \texttt{R} with High-Performance \texttt{C++} Linear Algebra",
3 | AUTHOR="Dirk Eddelbuettel and Conrad Sanderson",
4 | JOURNAL="Computational Statistics and Data Analysis",
5 | YEAR=2014,
6 | VOLUME=71,
7 | PAGES={1054-1063},
8 | DOI="10.1016/j.csda.2013.02.005"
9 | }
10 | @ARTICLE{Eddelbuettel:2011,
11 | TITLE="\texttt{Rcpp}: Seamless \texttt{R} and \texttt{C++} Integration",
12 | AUTHOR="Dirk Eddelbuettel and Romain Fran\c{c}ois",
13 | JOURNAL="Journal of Statistical Software",
14 | YEAR=2011,
15 | VOLUME=40,
16 | NUMBER=8,
17 | DOI="10.18637/jss.v040.i08",
18 | PAGES={1-18}
19 | }
20 | @ARTICLE{Sanderson:2016,
21 | TITLE="\texttt{Armadillo}: A Template-Based \texttt{C++} Library for Linear Algebra",
22 | AUTHOR="Conrad Sanderson and Ryan Curtin",
23 | YEAR=2016,
24 | JOURNAL="Journal of Open Source Software",
25 | VOLUME=1,
26 | NUMBER=2,
27 | PAGES={26},
28 | DOI="10.21105/joss.00026"
29 | }
30 |
--------------------------------------------------------------------------------