00001 /* This program is free software: you can redistribute it and/or modify 00002 * it under the terms of the GNU General Public License as published by 00003 * the Free Software Foundation, either version 3 of the License, or 00004 * (at your option) any later version. 00005 * 00006 * This program is distributed in the hope that it will be useful, 00007 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00008 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00009 * GNU General Public License for more details. 00010 * 00011 * You should have received a copy of the GNU General Public License 00012 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00013 * 00014 * Copyright (C) 2009 - 2012 Jun Liu and Jieping Ye 00015 */ 00016 00017 #ifndef OVERLAPPING_SLEP 00018 #define OVERLAPPING_SLEP 00019 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 #include <math.h> 00023 #include <string.h> 00024 00025 00026 /* 00027 * ------------------------------------------------------------------- 00028 * Function and parameter 00029 * ------------------------------------------------------------------- 00030 * 00031 * In this file, we focus solving the following problem 00032 * 00033 * 1/2 \|x-v\|^2 + \lambda_1 \|x\|_1 + \lambda_2 \sum w_i \|x_{G_i}\|, 00034 * 00035 * where x and v are of dimension p, 00036 * w >0, and G_i contains the indices for the i-th group 00037 * 00038 * The file is implemented in the following in Matlab: 00039 * 00040 * x=overlapping(v, p, g, lambda1, lambda2, w, G, Y, maxIter, flag, tol); 00041 * 00042 * x and v are vectors of dimension p 00043 * 00044 * g denotes the number of groups 00045 * 00046 * lambda1 and labmda2 are non-negative regularization paramter 00047 * 00048 * G is a vector containing the indices for the groups 00049 * G_1, G_2, ..., G_g 00050 * 00051 * w is a 3xg matrix 00052 * w(1,i) contains the starting index of the i-th group in G 00053 * w(2,i) contains the ending index of the i-th group in G 00054 * w(3,i) contains the weight for the i-th group 00055 * 00056 * Y is the dual of \|x_{G_i}\|, it is of the same size as G 00057 * 00058 * maxIter is the maximal number of iteration 00059 * 00060 * flag=0, we apply the pure projected gradient descent 00061 * (forward and backward line search is used) 00062 * 00063 * flag=1, we apply the projected gradient descent with restart 00064 * 00065 * in the future, we may apply the accelerated gradient descent 00066 * with adaptive line search (see our KDD'09 paper) with other "flag" 00067 * 00068 * 00069 * Note: 00070 * 00071 * 1. One should ensure w(2,i)-w(1,i)+1=|G_i|. 00072 * !! The program does not check w(2,i)-w(1,i)+1=|G_i|.!! 00073 * 00074 * 2. The index in G and w starts from 0 00075 * 00076 * ------------------------------------------------------------------- 00077 * History: 00078 * ------------------------------------------------------------------- 00079 * 00080 * Composed by Jun Liu on May 17, 2010 00081 * 00082 * For any question or suggestion, please email j.liu@asu.edu or 00083 * jun.liu.80@gmail.com 00084 * 00085 */ 00086 00087 00088 /* 00089 * -------------------------------------------------------------------- 00090 * Identifying some zero Entries 00091 * -------------------------------------------------------------------- 00092 * 00093 * lambda1, lambda2 should be non-negative 00094 * 00095 * v is the vector of size p to be projected 00096 * 00097 * 00098 * zeroGroupFlag is a vector of size g 00099 * 00100 * zeroGroupFlag[i]=0 denotes that the corresponding group is definitely zero 00101 * zeroGroupFlag[i]=1 denotes that the corresponding group is (possibly) nonzero 00102 * 00103 * 00104 * u is a vector of size p 00105 * 00106 * 00107 * entrySignFlag is a vector of size p 00108 * 00109 * entrySignFlag[i]=0 denotes that the corresponding entry is definitely zero 00110 * entrySignFlag[i]=1 denotes that the corresponding entry is (possibly) positive 00111 * entrySignFlag[i]=-1 denotes that the corresponding entry is (possibly) negative 00112 * 00113 */ 00114 void identifySomeZeroEntries(double * u, int * zeroGroupFlag, int *entrySignFlag, 00115 int *pp, int *gg, 00116 double *v, double lambda1, double lambda2, 00117 int p, int g, double * w, double *G); 00118 00119 /* 00120 * 00121 * function: xFromY 00122 * 00123 * compute x=max(u-Y * e, 0); 00124 * 00125 * xFromY(x, y, u, Y, p, g, zeroGroupFlag, G, w); 00126 * 00127 * y=u-Y * e - max( u - Y * e, 0) 00128 * 00129 */ 00130 void xFromY(double *x, double *y, 00131 double *u, double *Y, 00132 int p, int g, int *zeroGroupFlag, 00133 double *G, double *w); 00134 00135 /* 00136 * 00137 * function: YFromx 00138 * 00139 * compute Y=subgradient(x) 00140 * 00141 * YFromx(Y, xnew, Ynew, lambda2, g, zeroGroupFlag, G, w); 00142 * 00143 * The idea is that, if x_{G_i} is nonzero, 00144 * we compute Y^i as x_{G_i}/ \|x_{G_i}\| * lambda2 * w[3*i+2] 00145 * otherwise 00146 * Y^i=Ynew^i 00147 * 00148 */ 00149 void YFromx(double *Y, 00150 double *xnew, double *Ynew, 00151 double lambda2, int g, int *zeroGroupFlag, 00152 double *G, double *w); 00153 00154 /* 00155 * function: dualityGap 00156 * 00157 * compute the duality gap for the approximate solution (x, Y) 00158 * 00159 * Meanwhile, we compute 00160 * 00161 * penalty2=\sum_{i=1}^g w_i \|x_{G_i}\| 00162 * 00163 */ 00164 void dualityGap(double *gap, double *penalty2, 00165 double *x, double *Y, int g, int *zeroGroupFlag, 00166 double *G, double *w, double lambda2); 00167 00168 /* 00169 * we solve the proximal opeartor: 00170 * 00171 * 1/2 \|x-v\|^2 + \lambda_1 \|x\|_1 + \lambda_2 \sum w_i \|x_{G_i}\| 00172 * 00173 * See the description of the variables in the beginning of this file 00174 * 00175 * x is the primal variable, each of its entry is non-negative 00176 * 00177 * Y is the dual variable, each of its entry should be non-negative 00178 * 00179 * flag =0: no restart 00180 * flag =1; restart 00181 * 00182 * tol: the precision parameter 00183 * 00184 * The following code apply the projected gradient descent method 00185 * 00186 */ 00187 void overlapping_gd(double *x, double *gap, double *penalty2, 00188 double *v, int p, int g, double lambda1, double lambda2, 00189 double *w, double *G, double *Y, int maxIter, int flag, double tol); 00190 00191 /* 00192 * 00193 * do a gradient descent step based (x, Y) to get (xnew, Ynew) 00194 * 00195 * (x, Y) is known. Here we do a line search for determining the value of L 00196 * 00197 * gradientDescentStep(double *xnew, double *Ynew, 00198 double *LL, double *u, 00199 double *x, double *Y, int p, int g, int * zeroGroupFlag, 00200 double *G, double *w) 00201 * 00202 */ 00203 void gradientDescentStep(double *xnew, double *Ynew, 00204 double *LL, double *u, double *y, int *entrySignFlag, double lambda2, 00205 double *x, double *Y, int p, int g, int * zeroGroupFlag, 00206 double *G, double *w); 00207 00208 /* 00209 * 00210 * we use the accelerated gradient descent 00211 * 00212 */ 00213 void overlapping_agd(double *x, double *gap, double *penalty2, 00214 double *v, int p, int g, double lambda1, double lambda2, 00215 double *w, double *G, double *Y, int maxIter, int flag, double tol); 00216 00217 /* 00218 * This is main function for the projection 00219 * 00220 * It calls overlapping_gd and overlapping_agd based on flag 00221 * 00222 * 00223 */ 00224 void overlapping(double *x, double *gap, double *penalty2, 00225 double *v, int p, int g, double lambda1, double lambda2, 00226 double *w, double *G, double *Y, int maxIter, int flag, double tol); 00227 00228 #endif /* ----- #ifndef OVERLAPPING_SLEP ----- */