SLIM  1.0
Sparse Linear Methods (SLIM) for top-n recommender systems
 All Data Structures Files Functions Variables Typedefs Macros Pages
bcsol.c
Go to the documentation of this file.
1 /**************************************************************/
2 /*! \file
3 
4  \brief This file contains all the routines needed for
5  BCLS optimization.
6 */
7 /**************************************************************/
8 
9 
10 
11 #include<slim.h>
12 
13 /*! \brief Number of iterations */
14 int bcls_niters = 0;
15 
16 /* The following macros are from BCLS */
17 /*! \brief Compute the maximum of two */
18 #define CS_MAX(a,b) (((a) > (b)) ? (a) : (b))
19 /*! \brief Compute the minimum of two */
20 #define CS_MIN(a,b) (((a) < (b)) ? (a) : (b))
21 /*! \brief Flip */
22 #define CS_FLIP(i) (-(i)-2)
23 /*! \brief Unflip */
24 #define CS_UNFLIP(i) (((i) < 0) ? CS_FLIP(i) : (i))
25 /*! \brief Check if marked */
26 #define CS_MARKED(w,j) (w [j] < 0)
27 /*! \brief Mark */
28 #define CS_MARK(w,j) { w [j] = CS_FLIP (w [j]) ; }
29 /*! \brief CSC */
30 #define CS_CSC(A) (A && (A->nz == -1))
31 /*! \brief Triplet*/
32 #define CS_TRIPLET(A) (A && (A->nz >= 0))
33 
34 
35 // Type of projected search.
36 static int proj_search = BCLS_PROJ_SEARCH_EXACT;
37 /* static int proj_search = BCLS_PROJ_SEARCH_APPROX; */
38 // Method for Newton step computation.
39 static int newton_step = BCLS_NEWTON_STEP_LSQR;
40 
41 
42 
43 /**************************************************************/
44 /*! \brief call_back function, periodically called by BCLS to
45  test if the user wants to exit. This is from BCLS.
46 */
47 /**************************************************************/
48 int call_back( BCLS *ls, void *UsrWrk ){
49  int err;
50  err = 0; /* No error. */
51  return err;
52 }
53 
54 /**************************************************************/
55 /*! \brief call_back function, immediately terminate BCLS
56  iterations based on how many iterations it runs
57 */
58 /**************************************************************/
59 int call_back_it( BCLS *ls, void *UsrWrk ){
60 
61  bcls_niters ++;
62  if (bcls_niters == ((worksp*)UsrWrk)->max_bcls_niters)
63  return 1;
64  else
65  return 0;
66 }
67 
68 
69 
70 /**************************************************************/
71 /*! \brief Pretty_printer, this is the print-routine that will
72  be used by BCLS for its output. This is from BCLS.
73 */
74 /**************************************************************/
75 int pretty_printer( void *io_file, char *msg ) {
76  fprintf( io_file, "%s", msg );
77  return 0;
78 }
79 
80 
81 /**************************************************************/
82 /*! \brief Wrapper for free
83  */
84 /**************************************************************/
85 void *cs_free (void *p){
86  if (p) free (p) ; /* free p if it is not already NULL */
87  return (NULL) ; /* return NULL to simplify the use of cs_free */
88 }
89 
90 
91 /**************************************************************/
92 /*! \brief Wrapper for malloc
93  */
94 /**************************************************************/
95 void *cs_malloc (int n, size_t size){
96  return (malloc (CS_MAX (n,1) * size)) ;
97 }
98 
99 /**************************************************************/
100 /*! \brief Wrapper for calloc
101 */
102 /**************************************************************/
103 void *cs_calloc (int n, size_t size){
104  return (calloc (CS_MAX (n,1), size)) ;
105 }
106 
107 
108 
109 /**************************************************************/
110 /*! \brief Free a sparse matrix
111  */
112 /**************************************************************/
114  if (!A) return (NULL) ; /* do nothing if A already NULL */
115  cs_free (A->p) ;
116  cs_free (A->i) ;
117  cs_free (A->x) ;
118  return (cs_free (A)) ; /* free the cs struct and return NULL */
119 }
120 
121 /**************************************************************/
122 /*! \brief Allocate a sparse matrix (triplet form or
123  compressed-column form)
124 */
125 /**************************************************************/
126 cs *cs_spalloc (int m, int n, int nzmax, int values, int triplet){
127  cs *A = cs_calloc (1, sizeof (cs)) ; /* allocate the cs struct */
128  if (!A) return (NULL) ; /* out of memory */
129  A->m = m ; /* define dimensions and nzmax */
130  A->n = n ;
131  A->nzmax = nzmax = CS_MAX (nzmax, 1) ;
132  A->nz = triplet ? 0 : -1 ; /* allocate triplet or comp.col */
133  A->p = cs_malloc (triplet ? nzmax : n+1, sizeof (int)) ;
134  A->i = cs_malloc (nzmax, sizeof (int)) ;
135  A->x = values ? cs_malloc (nzmax, sizeof (double)) : NULL ;
136  return ((!A->p || !A->i || (values && !A->x)) ? cs_spfree (A) : A) ;
137 }
138 
139 
140 /**************************************************************/
141 /*! \brief Load a constant into a vector
142  */
143 /**************************************************************/
144 void dload( const int n, const double alpha, double x[] ) {
145 
146  int j;
147  for (j = 0; j < n; j++) x[j] = alpha;
148  return;
149 }
150 
151 
152 
153 
154 /**************************************************************/
155 /*! \brief Aprod, matrix-vector products. This is from BCLS.
156 
157  \details
158  If mode == BCLS_PROD_A (0), compute y <- A *x, with x untouched;
159  and if mode == BCLS_PROD_At (1), compute x <- A'*y, with y untouched.
160 
161 */
162 /**************************************************************/
163 int Aprod( int mode, int m, int n, int nix, int ix[],
164  double x[], double y[], void *UsrWrk ) {
165 
166  int i, j, k, l;
167  double aij;
168  double xj, sum;
169  worksp * Wrk = (worksp *)UsrWrk;
170  cs *A = (cs *)Wrk->A;
171  int * Ai = A->i;
172  int * Ap = A->p;
173  float * Ax = A->x;
174  int * acol = Wrk->acol;
175 
176 
177  if (mode == BCLS_PROD_A) {
178 
179  gk_dset(m, 0.0, y);
180 
181  for (l = 0; l < nix; l++) {
182  j = ix[l];
183 
184  /* skip the inactive column */
185  if (!acol[j]) continue;
186 
187  xj = x[j];
188  if (xj == 0.0)
189  ; // Relax.
190  else
191  for (k = Ap[j]; k < Ap[j+1]; k++) {
192  aij = Ax[k];
193 
194 
195  /* this is to handle float-valued A matrix */
196  i = Ai[k];
197  y[i] += aij * xj;
198 
199 
200  }
201  }
202  }
203 
204  else if (mode == BCLS_PROD_At) {
205  for (l = 0; l < nix; l++) {
206  j = ix[l];
207  sum = 0;
208 
209  /* skip the inactive column */
210  if (!acol[j]){
211  x[j] = sum;
212  continue;
213  }
214 
215  for (k = Ap[j]; k < Ap[j+1]; k++) {
216  aij = Ax[k];
217 
218  /* this is to handle float-valued A matrix */
219  i = Ai[k];
220  sum += aij * y[i];
221 
222 
223  }
224  x[j] = sum;
225  }
226  }
227 
228 
229  return 0;
230 }
231 
232 
233 
234 /**************************************************************/
235 /*! \brief BCLS learning. This is from BCLS
236 
237  \details This is to solve the problem
238  \f[
239  \begin{array}{ll}
240  \displaystyle\mathop{\hbox{minimize}}_x & \frac12\|Ax-a_i\|_2^2 + \frac{1}{2}\beta\|x\|_2^2 + \lambda \|x\|_1 \\
241  \hbox{subject to} & 0 \le x \\
242  & x_i = 0 \\
243  \end{array}
244  \f]
245  */
246 /**************************************************************/
247 void bcsol(ctrl_t * ctrl, gk_csr_t * AA, double * bb, double * x, worksp * Wrk,
248  double * bl, double * bu,
249  double beta, double * c){
250 
251  bcls_niters = 0;
252 
253  /* Problem dimensions. */
254  int m = AA->nrows;
255  int n = AA->ncols;
256 
257  /* init a bcls problem */
258  BCLS *ls = bcls_create_prob( m, n );
259 
260  bcls_set_problem_data(ls, m, n, Aprod, Wrk, beta, x, bb, c, bl, bu);
261 
262 
263  /* set up tolerance */
264  ls->optTol = ctrl->optTol;
265 
266  /* whatever */
267  bcls_set_print_hook( ls, stdout, pretty_printer );
268  ls->proj_search = proj_search;
269  ls->newton_step = newton_step;
270  /* if (ctrl->test_bcls) */
271  if (ctrl->max_bcls_niters > 0)
272  ls->CallBack = call_back_it;
273  else
274  ls->CallBack = call_back;
275 
276  /* call the solver */
277  int err = bcls_solve_prob( ls );
278 
279  /* solution */
280  if (ctrl->dbglvl > 1){
281  int nnzx = 0;
282  printf("\n Solution\n --------\n");
283  printf("%4s %18s %1s %18s %1s %18s %18s\n",
284  "Var","Lower","","Value","","Upper","Gradient");
285  for (int j = 0; j < n; j++) {
286  if (x[j] > 1e-10){
287  nnzx ++;
288  char * blActiv = "";
289  char * buActiv = "";
290  if (x[j] - bl[j] < ls->epsx) blActiv = "=";
291  if (bu[j] - x[j] < ls->epsx) buActiv = "=";
292  printf("%4d %18.11e %1s %18.11e %1s %18.11e %18.11e\n",
293  j+1, bl[j], blActiv, x[j], buActiv, bu[j], (ls->g)[j]);
294  }
295  }
296  printf("%d nnz solution values\n", nnzx);
297  }
298 
299 
300  /* free the problem */
301  err = bcls_free_prob( ls );
302 
303 }
304