blob: 3edadd9aabf49a62e17ff1b63d2fb1eb54b47881 [file] [log] [blame]
#-------------------------------------------------------------
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#-------------------------------------------------------------
# Builtin function for the SpaRSA algorithm to perform lasso regression
# (SpaRSA .. Sparse Reconstruction by Separable Approximation)
#
# INPUTS:
# ---------------------------------------------------------------------------------------------
# NAME TYPE DEFAULT MEANING
# ---------------------------------------------------------------------------------------------
# X Double --- input feature matrix
# y Double --- matrix Y columns of the design matrix
# tol Double 1e-15 target convergence tolerance
# M Integer 5 history length
# tau Double 1 regularization component
# maxi Integer 100 maximum number of iterations until convergence
# ---------------------------------------------------------------------------------------------
# OUTPUTS
# w Double --- model matrix
m_lasso = function(Matrix[Double] X, Matrix[Double] y, Double tol = 10^(-15),
Integer M = 5, Double tau = 1, Integer maxi = 100, Boolean verbose = TRUE)
return(Matrix[Double] w)
{
n = nrow(X)
m = ncol(X)
#constants
eta = 2
sigma = 0.01
alpha_min = 10^(-30)
alpha_max = 10^(30)
#init
alpha = 1
w = Rand(rows=m, cols=1, min=0, max=1, pdf="uniform")
history = -1e30 * matrix(1, rows=M, cols=1)
r = X %*% w - y
g = t(X) %*% r
obj = 0.5 * sum(r*r) + tau*sum(abs(w))
if( verbose )
print("Initial OBJ=" + obj)
history[M,1] = obj
inactive_set = matrix(1, rows=m, cols=1)
iter = 0
continue = TRUE
while(iter < maxi & continue) {
dw = matrix(0, rows=m, cols=1)
dg = matrix(0, rows=m, cols=1)
relChangeObj = -1.0
inner_iter = 0
inner_continue = TRUE
inner_maxiter = 100
while(inner_iter < inner_maxiter & inner_continue) {
u = w - g/alpha
lambda = tau/alpha
wnew = sign(u) * (abs(u) - lambda) * ((abs(u) - lambda) > 0)
dw = wnew - w
dw2 = sum(dw*dw)
r = X %*% wnew - y
gnew = t(X) %*% r
objnew = 0.5 * sum(r*r) + tau*sum(abs(wnew))
obj_threshold = max(history) - 0.5*sigma*alpha*dw2
if(objnew <= obj_threshold) {
w = wnew
dg = gnew - g
g = gnew
inner_continue = FALSE
history[1:(M-1),] = history[2:M,]
history[M,1] = objnew
relChangeObj = abs(objnew - obj)/obj
obj = objnew
}
else
alpha = eta*alpha
inner_iter = inner_iter + 1
}
if(inner_continue)
print("Inner loop did not converge")
alphanew = sum(dw*dg)/sum(dw*dw)
alpha = max(alpha_min, min(alpha_max, alphanew))
old_inactive_set = inactive_set
inactive_set = w != 0
diff = sum(abs(old_inactive_set - inactive_set))
continue = (diff != 0 | relChangeObj >= tol)
num_inactive = sum(w != 0)
if( verbose )
print("ITER=" + iter + " OBJ=" + obj + " relative change=" + relChangeObj + " num_inactive=" + num_inactive)
iter = iter + 1
}
}