@@ -40,27 +40,28 @@ get_incidence_from_adjacency <- function(A) {
4040# ' IEEE Trans. on Signal Processing, vol. 67, no. 16, pp. 4231-4244, Aug. 2019
4141
4242# ' @export
43- learn_laplacian_gle_mm <- function (S , A , alpha = 0 , maxiter = 10000 , reltol = 1e-5 ,
44- abstol = 1e-5 , record_objective = FALSE ,
45- verbose = TRUE ) {
43+ learn_laplacian_gle_mm <- function (S , A_mask = NULL , alpha = 0 , maxiter = 10000 , reltol = 1e-5 ,
44+ record_objective = FALSE , verbose = TRUE ) {
45+ # number of nodes
46+ p <- nrow(S )
4647 Sinv <- MASS :: ginv(S )
47- mask <- Ainv(A ) > 0
48+ if (is.null(A_mask ))
49+ A_mask <- matrix (1 , p , p ) - diag(p )
50+ mask <- Ainv(A_mask ) > 0
4851 w <- w_init(" naive" , Sinv )[mask ]
4952 wk <- w
50- # number of nodes
51- p <- nrow(S )
5253 # number of nonzero edges
53- m <- .5 * sum(A > 0 )
54+ m <- sum( mask ) # .5 * sum(A_mask > 0)
5455 # l1-norm penalty factor
5556 J <- matrix (1 , p , p ) / p
5657 H <- 2 * diag(p ) - p * J
5758 K <- S + alpha * H
58- E <- get_incidence_from_adjacency(A )
59+ E <- get_incidence_from_adjacency(A_mask )
5960 R <- t(E ) %*% K %*% E
6061 r <- nrow(R )
6162 G <- cbind(E , rep(1 , p ))
6263 if (record_objective )
63- fun <- obj_func( E , K , wk , J )
64+ fun <- vanilla.objective(L( wk ), K )
6465 if (verbose )
6566 pb <- progress :: progress_bar $ new(format = " <:bar> :current/:total eta: :eta" ,
6667 total = maxiter , clear = FALSE , width = 80 )
@@ -72,11 +73,10 @@ learn_laplacian_gle_mm <- function(S, A, alpha = 0, maxiter = 10000, reltol = 1e
7273 Q <- Q [1 : m , 1 : m ]
7374 wk <- sqrt(diag(Q ) / diag(R ))
7475 if (record_objective )
75- fun <- c(fun , obj_func( E , K , wk , J ))
76+ fun <- c(fun , vanilla.objective(L( wk ), K ))
7677 if (verbose )
7778 pb $ tick()
78- werr <- abs(w - wk )
79- has_converged <- all(werr < = .5 * reltol * (w + wk )) || all(werr < = abstol )
79+ has_converged <- norm(w - wk , " 2" ) / norm(w , " 2" ) < reltol
8080 if (has_converged && k > 1 ) break
8181 w <- wk
8282 }
@@ -89,6 +89,7 @@ learn_laplacian_gle_mm <- function(S, A, alpha = 0, maxiter = 10000, reltol = 1e
8989 return (results )
9090}
9191
92+
9293obj_func <- function (E , K , w , J ) {
9394 p <- ncol(J )
9495 EWEt <- E %*% diag(w ) %*% t(E )
@@ -117,17 +118,20 @@ obj_func <- function(E, K, w, J) {
117118# ' Optimization Algorithms for Graph Laplacian Estimation via ADMM and MM.
118119# ' IEEE Trans. on Signal Processing, vol. 67, no. 16, pp. 4231-4244, Aug. 2019
119120# ' @export
120- learn_laplacian_gle_admm <- function (S , A , alpha = 0 , rho = 1 , maxiter = 10000 ,
121- reltol = 1e-5 , record_objective = FALSE ,
122- verbose = TRUE ) {
121+ learn_laplacian_gle_admm <- function (S , A_mask = NULL , alpha = 0 , rho = 1 , maxiter = 10000 ,
122+ reltol = 1e-5 , record_objective = FALSE , verbose = TRUE ) {
123123 p <- nrow(S )
124+ if (is.null(A_mask ))
125+ A_mask <- matrix (1 , p , p ) - diag(p )
124126 Sinv <- MASS :: ginv(S )
125127 w <- w_init(" naive" , Sinv )
126128 Yk <- L(w )
127129 Theta <- Yk
128- P <- eigvec_sym(Yk )
129- P <- P [, 2 : p ]
130130 Ck <- Yk
131+ C <- Ck
132+ # ADMM constants
133+ mu <- 2
134+ tau <- 2
131135 # l1-norm penalty factor
132136 J <- matrix (1 , p , p ) / p
133137 H <- 2 * diag(p ) - p * J
@@ -136,23 +140,35 @@ learn_laplacian_gle_admm <- function(S, A, alpha = 0, rho = 1, maxiter = 10000,
136140 pb <- progress :: progress_bar $ new(format = " <:bar> :current/:total eta: :eta" ,
137141 total = maxiter , clear = FALSE , width = 80 )
138142 if (record_objective )
139- fun <- c()
143+ fun <- c(vanilla.objective( Theta , K ) )
140144 # ADMM loop
145+ # P <- qr.Q(qr(rep(1, p)), complete=TRUE)[, 2:p]
146+ P <- eigvec_sym(Yk )
147+ P <- P [, 2 : p ]
141148 for (k in c(1 : maxiter )) {
142149 Gamma <- t(P ) %*% (K + Yk - rho * Ck ) %*% P
143150 U <- eigvec_sym(Gamma )
144151 lambda <- eigval_sym(Gamma )
145152 d <- .5 * c(sqrt(lambda ^ 2 + 4 / rho ) - lambda )
146153 Xik <- crossprod(sqrt(d ) * t(U ))
147154 Thetak <- P %*% Xik %*% t(P )
148- Ck <- (diag(pmax(0 , diag(Yk / rho + Thetak ))) +
149- A * pmin(0 , Yk / rho + Thetak ))
150- Yk <- Yk + rho * (Thetak - Ck )
155+ Ck_tmp <- Yk / rho + Thetak
156+ Ck <- (diag(pmax(0 , diag(Ck_tmp ))) +
157+ A_mask * pmin(0 , Ck_tmp ))
158+ Rk <- Thetak - Ck
159+ Yk <- Yk + rho * Rk
151160 if (record_objective )
152- fun <- c(fun , aug_lag(K , P , Xik , Yk , Ck , d , rho ))
153- has_converged <- norm(Theta - Thetak , " F" ) / norm(Thetak , " F" ) < reltol
161+ fun <- c(fun , vanilla.objective(Thetak , K ))
162+ normF_Rk <- norm(Rk , " F" )
163+ has_converged <- norm(Theta - Thetak ) / norm(Theta , " F" ) < reltol
154164 if (has_converged && k > 1 ) break
165+ # s <- rho * norm(C - Ck, "F")
166+ # if (normF_Rk > mu * s)
167+ # rho <- rho * tau
168+ # else if (s > mu * normF_Rk)
169+ # rho <- rho / tau
155170 Theta <- Thetak
171+ C <- Ck
156172 if (verbose )
157173 pb $ tick()
158174 }
0 commit comments