SLIM  1.0
Sparse Linear Methods (SLIM) for top-n recommender systems
 All Data Structures Files Functions Variables Typedefs Macros Pages
Functions
proto.h File Reference

This file contains all prototypes. More...

Go to the source code of this file.

Functions

void parse_cmdline (ctrl_t *ctrl, int argc, char *argv[])
 Entry point of the command-line argument parsing.
 
ctrl_tcreate_ctrl ()
 Create a ctrl structure wich contains all the default parameters for SLIM.
 
void free_ctrl (ctrl_t *ctrl)
 Free a ctrl structure.
 
void start_timer (ctimer_t *ctimer)
 Start a timer to record current time.
 
void end_timer (ctimer_t *ctimer)
 End a timer to record a length of a duration.
 
void display_timer (ctimer_t *ctimer, char *msg)
 Display a user-defined message and a duration length recorded by a timer.
 
int count_nnz (double *array, int narray)
 Count the number of non-zero values in an array.
 
void find_topk (double *w, int n, int topk, double *map, int *topk2)
 Find the top-k values from an array.
 
void get_column (gk_csr_t *constraint, int i, double *w)
 Get a column from a csr matrix.
 
gk_csr_t * read_constraint (ctrl_t *ctrl, char *file)
 Read in a constraint matrix for feature selection.
 
void csr_Write (gk_csr_t *mat, char *filename, char *mode, int format, int writevals, int numbering)
 Dump the csr into a file.
 
void check_train_test (ctrl_t *ctrl, gk_csr_t *train, gk_csr_t *test)
 Check if test data are already in train data.
 
int call_back (BCLS *ls, void *UsrWrk)
 call_back function, periodically called by BCLS to test if the user wants to exit. This is from BCLS.
 
int call_back_it (BCLS *ls, void *UsrWrk)
 call_back function, immediately terminate BCLS iterations based on how many iterations it runs
 
int pretty_printer (void *io_file, char *msg)
 Pretty_printer, this is the print-routine that will be used by BCLS for its output. This is from BCLS.
 
void * cs_free (void *p)
 Wrapper for free.
 
void * cs_malloc (int n, size_t size)
 Wrapper for malloc.
 
void * cs_calloc (int n, size_t size)
 Wrapper for calloc.
 
cscs_spfree (cs *A)
 Free a sparse matrix.
 
cscs_spalloc (int m, int n, int nzmax, int values, int triplet)
 Allocate a sparse matrix (triplet form or compressed-column form)
 
void dload (const int n, const double alpha, double x[])
 Load a constant into a vector.
 
int Aprod (int mode, int m, int n, int nix, int ix[], double x[], double y[], void *UsrWrk)
 Aprod, matrix-vector products. This is from BCLS.
 
void bcsol (ctrl_t *ctrl, gk_csr_t *AA, double *bb, double *x, worksp *Wrk, double *bl, double *bu, double beta, double *c)
 BCLS learning. This is from BCLS.
 
void slim_learn (ctrl_t *ctrl, gk_csr_t *train)
 SLIM learning.
 
void slim_fs_learn (ctrl_t *ctrl, gk_csr_t *A, double *b, double *w, float **A_colval, worksp *Wrk, double *bl, double *bu, double beta, double *c)
 SLIM learning with feature selction.
 
void preprocess (ctrl_t *ctrl, gk_csr_t *train, gk_csr_t *test)
 Pre-process the data.
 
double * slim_test (ctrl_t *ctrl, gk_csr_t *model, gk_csr_t *train, gk_csr_t *test)
 Top-N recommendations and evaluations.
 
int suggest_predict (ctrl_t *ctrl, gk_csr_t *model, int **iidx, gk_csr_t *train, int u, gk_dkv_t **rcmd)
 Top-N recommendation for a user.
 
void slim_predict (ctrl_t *ctrl, gk_csr_t *train, gk_csr_t *test, gk_csr_t *model)
 SLIM testing.
 

Detailed Description

This file contains all prototypes.

Definition in file proto.h.

Function Documentation

int Aprod ( int  mode,
int  m,
int  n,
int  nix,
int  ix[],
double  x[],
double  y[],
void *  UsrWrk 
)

Aprod, matrix-vector products. This is from BCLS.

If mode == BCLS_PROD_A (0), compute y <- A *x, with x untouched; and if mode == BCLS_PROD_At (1), compute x <- A'*y, with y untouched.

Definition at line 163 of file bcsol.c.

References worksp::A, worksp::acol, cs_sparse::i, cs_sparse::p, and cs_sparse::x.

Referenced by bcsol().

{
int i, j, k, l;
double aij;
double xj, sum;
worksp * Wrk = (worksp *)UsrWrk;
cs *A = (cs *)Wrk->A;
int * Ai = A->i;
int * Ap = A->p;
float * Ax = A->x;
int * acol = Wrk->acol;
if (mode == BCLS_PROD_A) {
gk_dset(m, 0.0, y);
for (l = 0; l < nix; l++) {
j = ix[l];
/* skip the inactive column */
if (!acol[j]) continue;
xj = x[j];
if (xj == 0.0)
; // Relax.
else
for (k = Ap[j]; k < Ap[j+1]; k++) {
aij = Ax[k];
/* this is to handle float-valued A matrix */
i = Ai[k];
y[i] += aij * xj;
}
}
}
else if (mode == BCLS_PROD_At) {
for (l = 0; l < nix; l++) {
j = ix[l];
sum = 0;
/* skip the inactive column */
if (!acol[j]){
x[j] = sum;
continue;
}
for (k = Ap[j]; k < Ap[j+1]; k++) {
aij = Ax[k];
/* this is to handle float-valued A matrix */
i = Ai[k];
sum += aij * y[i];
}
x[j] = sum;
}
}
return 0;
}
void bcsol ( ctrl_t ctrl,
gk_csr_t *  AA,
double *  bb,
double *  x,
worksp Wrk,
double *  bl,
double *  bu,
double  beta,
double *  c 
)

BCLS learning. This is from BCLS.

This is to solve the problem

\[ \begin{array}{ll} \displaystyle\mathop{\hbox{minimize}}_x & \frac12\|Ax-a_i\|_2^2 + \frac{1}{2}\beta\|x\|_2^2 + \lambda \|x\|_1 \\ \hbox{subject to} & 0 \le x \\ & x_i = 0 \\ \end{array} \]

Definition at line 247 of file bcsol.c.

References Aprod(), bcls_niters, call_back(), call_back_it(), ctrl_t::dbglvl, ctrl_t::max_bcls_niters, ctrl_t::optTol, and pretty_printer().

Referenced by slim_fs_learn(), and slim_learn().

{
/* Problem dimensions. */
int m = AA->nrows;
int n = AA->ncols;
/* init a bcls problem */
BCLS *ls = bcls_create_prob( m, n );
bcls_set_problem_data(ls, m, n, Aprod, Wrk, beta, x, bb, c, bl, bu);
/* set up tolerance */
ls->optTol = ctrl->optTol;
/* whatever */
bcls_set_print_hook( ls, stdout, pretty_printer );
ls->proj_search = proj_search;
ls->newton_step = newton_step;
/* if (ctrl->test_bcls) */
if (ctrl->max_bcls_niters > 0)
ls->CallBack = call_back_it;
else
ls->CallBack = call_back;
/* call the solver */
int err = bcls_solve_prob( ls );
/* solution */
if (ctrl->dbglvl > 1){
int nnzx = 0;
printf("\n Solution\n --------\n");
printf("%4s %18s %1s %18s %1s %18s %18s\n",
"Var","Lower","","Value","","Upper","Gradient");
for (int j = 0; j < n; j++) {
if (x[j] > 1e-10){
nnzx ++;
char * blActiv = "";
char * buActiv = "";
if (x[j] - bl[j] < ls->epsx) blActiv = "=";
if (bu[j] - x[j] < ls->epsx) buActiv = "=";
printf("%4d %18.11e %1s %18.11e %1s %18.11e %18.11e\n",
j+1, bl[j], blActiv, x[j], buActiv, bu[j], (ls->g)[j]);
}
}
printf("%d nnz solution values\n", nnzx);
}
/* free the problem */
err = bcls_free_prob( ls );
}
void check_train_test ( ctrl_t ctrl,
gk_csr_t *  train,
gk_csr_t *  test 
)

Check if test data are already in train data.

Parameters
[in]ctrlA ctrl structure
[in]trainThe training data
[in]testThe testing data

Definition at line 19 of file check.c.

Referenced by preprocess().

{
int error = 0;
int nrows_test = test->nrows;
for (int i = 0; i < nrows_test; i ++){
int nc_test = test->rowptr[i+1] - test->rowptr[i];
int nc_train = train->rowptr[i+1] - train->rowptr[i];
for (int j = 0; j < nc_test; j ++){
int item_test = *(test->rowptr[i] + j + test->rowind);
for (int k = 0; k < nc_train; k ++){
int item_train = *(train->rowptr[i] + k + train->rowind);
if (item_test == item_train){
printf("ERROR: user %6d has item %6d in both train and test\n", i, item_train);
error = 1;
break;
}
}
}
}
if (error)
errexit("ERROR: train and test not disjoint\n");
}
int count_nnz ( double *  array,
int  narray 
)

Count the number of non-zero values in an array.

Parameters
[in]arrayAn array whose non-zero values will be counted
[in]narrayThe length of the array
Returns
int The number of non-zero values in the array

Definition at line 134 of file util.c.

References EPSILON2.

Referenced by slim_fs_learn().

{
int nnz = 0;
for (int i = 0; i < narray; i ++){
if (array[i] > EPSILON2 || array[i] < -EPSILON2)
nnz ++;
}
return nnz;
}
ctrl_t* create_ctrl ( )

Create a ctrl structure wich contains all the default parameters for SLIM.

Returns
ctrl_t* A pointer to a created ctrl structure

Definition at line 21 of file util.c.

References ctrl_t::beta, ctrl_t::bl, ctrl_t::bsize, ctrl_t::bu, ctrl_t::dbglvl, ctrl_t::endi, ctrl_t::fs, ctrl_t::fs_file, ctrl_t::k, ctrl_t::lambda, ctrl_t::max_bcls_niters, ctrl_t::model_file, ctrl_t::nratings, ctrl_t::optTol, ctrl_t::pred_file, ctrl_t::starti, ctrl_t::test_file, ctrl_t::topn, ctrl_t::train_file, and ctrl_t::transpose.

Referenced by main(), and parse_cmdline().

{
ctrl_t * ctrl = gk_malloc(sizeof(ctrl_t), "malloc ctrl");
ctrl->train_file = NULL;
ctrl->test_file = NULL;
ctrl->model_file = NULL;
ctrl->fs_file = NULL;
ctrl->pred_file = NULL;
ctrl->dbglvl = 0;
ctrl->beta = 1.0;
ctrl->lambda = 1.0;
ctrl->starti = -1;
ctrl->endi = -1;
ctrl->optTol = 1e-5;
ctrl->max_bcls_niters = 100000;
ctrl->bl = 0;
ctrl->bu = 1e20;
ctrl->fs = 0;
ctrl->k = 50;
ctrl->bsize = 1000;
ctrl->nratings = 5;
ctrl->topn = 10;
ctrl->transpose = 0;
return ctrl;
}
void display_timer ( ctimer_t ctimer,
char *  msg 
)

Display a user-defined message and a duration length recorded by a timer.

Parameters
[in]ctimerA timer with a length of a duration recorded
[in]msgA user-defined message to display

Definition at line 116 of file util.c.

References ctimer_t::end, and ctimer_t::start.

Referenced by slim_learn(), and slim_test().

{
printf("----- elapsed CPU time for %s: %f s\n", msg,
(double)(ctimer->end - ctimer->start)/CLOCKS_PER_SEC);
fflush(stdout);
}
void end_timer ( ctimer_t ctimer)

End a timer to record a length of a duration.

Parameters
[in]ctimerA timer to end

Definition at line 101 of file util.c.

References ctimer_t::end.

Referenced by slim_learn(), and slim_test().

{
ctimer->end = clock();
}
void find_topk ( double *  w,
int  n,
int  topk,
double *  map,
int *  topk2 
)

Find the top-k values from an array.

Parameters
[in]wThe array whose top-k values will be found
[in]nThe length of the array w
[in]topkThe number of top values to be found
[out]mapThe array of indices that correspond to the top-k values in the input array
[out]topk2The actual number of top values that are found

Definition at line 159 of file util.c.

Referenced by slim_fs_learn().

{
gk_dkv_t * wkv = gk_malloc(sizeof(gk_dkv_t)*n, "malloc wkv");
int k2 = 0;
for (int i = 0; i < n; i ++){
wkv[i].key = w[i];
wkv[i].val = i;
if (w[i] > 1e-10) k2 ++;
}
/* sort */
gk_dkvsortd(n, wkv);
for (int i = 0; i < ((topk <= k2)? topk:k2); i ++){
map[i] = wkv[i].val;
}
*topk2 = ((topk <= k2)? topk:k2);
gk_free((void **)&wkv, LTERM);
}
void free_ctrl ( ctrl_t ctrl)

Free a ctrl structure.

Parameters
[in]ctrlA pointer to a ctrl structure to be freed

Definition at line 68 of file util.c.

References ctrl_t::fs_file, ctrl_t::model_file, ctrl_t::pred_file, ctrl_t::test_file, and ctrl_t::train_file.

Referenced by main().

{
gk_free((void **)&ctrl->model_file, LTERM);
gk_free((void **)&ctrl->train_file, LTERM);
gk_free((void **)&ctrl->test_file, LTERM);
gk_free((void **)&ctrl->pred_file, LTERM);
gk_free((void **)&ctrl->fs_file, LTERM);
gk_free((void **)&ctrl, LTERM);
}
void get_column ( gk_csr_t *  constraint,
int  i,
double *  w 
)

Get a column from a csr matrix.

Parameters
[in]constraintA matrix from which one column is to be retrievd
[in]iThe index of the column to be retrieved
[out]wThe output vector which saves the retrieved column

Definition at line 194 of file util.c.

Referenced by slim_learn().

{
if (i > constraint->ncols){
gk_dset(constraint->nrows, 0, w);
}
else{
int nnz = constraint->colptr[i+1] - constraint->colptr[i];
for (int j = 0; j < nnz; j ++){
int k = *(constraint->colptr[i] + j + constraint->colind);
w[k] = *(constraint->colptr[i] + j + constraint->colval);
}
}
}
void parse_cmdline ( ctrl_t ctrl,
int  argc,
char *  argv[] 
)

Entry point of the command-line argument parsing.

Parameters
[out]ctrlA ctrl structure to be filled out
[in]argcNumber of arguments
[in]argvA list of arguments

Definition at line 146 of file cmd.c.

References ctrl_t::beta, ctrl_t::bsize, CMD_BETA, CMD_BSIZE, CMD_DBGLVL, CMD_ENDI, CMD_FS, CMD_FS_FILE, CMD_HELP, CMD_K, CMD_LAMBDA, CMD_MAX_BCLS_NITERS, CMD_MODEL_FILE, CMD_NRATINGS, CMD_OPTTOL, CMD_PRED_FILE, CMD_STARTI, CMD_TEST_FILE, CMD_TOPN, CMD_TRAIN_FILE, CMD_TRANSPOSE, create_ctrl(), ctrl_t::dbglvl, ctrl_t::endi, ctrl_t::fs, ctrl_t::fs_file, ctrl_t::k, ctrl_t::lambda, ctrl_t::max_bcls_niters, ctrl_t::model_file, ctrl_t::nratings, ctrl_t::optTol, ctrl_t::pred_file, ctrl_t::starti, ctrl_t::test_file, ctrl_t::topn, ctrl_t::train_file, and ctrl_t::transpose.

Referenced by main().

{
int c = -1, option_index = -1;
if (ctrl == NULL)
ctrl = create_ctrl();
while((c = gk_getopt_long_only(argc, argv, "", slim_options, &option_index)) != -1){
switch(c){
ctrl->train_file = gk_strdup(gk_optarg);
break;
ctrl->test_file = gk_strdup(gk_optarg);
break;
ctrl->model_file = gk_strdup(gk_optarg);
break;
ctrl->pred_file = gk_strdup(gk_optarg);
break;
case CMD_DBGLVL:
ctrl->dbglvl = atoi(gk_optarg);
break;
case CMD_LAMBDA:
ctrl->lambda = atof(gk_optarg);
break;
case CMD_BETA:
ctrl->beta = atof(gk_optarg);
break;
case CMD_STARTI:
ctrl->starti = atoi(gk_optarg);
break;
case CMD_ENDI:
ctrl->endi = atoi(gk_optarg);
break;
case CMD_OPTTOL:
ctrl->optTol = atof(gk_optarg);
break;
ctrl->max_bcls_niters = atoi(gk_optarg);
break;
case CMD_FS:
ctrl->fs = 1;
break;
ctrl->fs_file = gk_strdup(gk_optarg);
break;
case CMD_K:
ctrl->k = atoi(gk_optarg);
break;
case CMD_BSIZE:
ctrl->bsize = atoi(gk_optarg);
break;
ctrl->nratings = atoi(gk_optarg);
break;
case CMD_TOPN:
ctrl->topn = atoi(gk_optarg);
break;
ctrl->transpose = 1;
break;
case CMD_HELP:
for (int i=0; strlen(helpstr[i]) > 0; i++)
printf("%s\n", helpstr[i]);
exit(0);
case '?':
default:
printf("Illegal command-line option(s) %s\n", gk_optarg);
exit(0);
}
}
if (argc-gk_optind != 0 || argc == 1) {
for (int i=0; strlen(shorthelpstr[i]) > 0; i++)
printf("%s\n", shorthelpstr[i]);
exit(0);
}
}
void slim_fs_learn ( ctrl_t ctrl,
gk_csr_t *  A,
double *  b,
double *  w,
float **  A_colval,
worksp Wrk,
double *  bl,
double *  bu,
double  beta,
double *  c 
)

SLIM learning with feature selction.

Parameters
[in]ctrlA ctrl structure which contains all the parameters for SLIM Learning with feature selection
[in]AThe A matrix
[in]bThe RHS vector
[in,out]wThe solution vector
[in]A_colvalA temporary place for a column
[in]WrkA workspace for BCLS
[in]blThe lower bound for BCLS
[in]buThe upper bound for BCLS
[in]betaThe regularization parameter for L-2 norm
[in]cThe vector for L-1 norm

Definition at line 31 of file slim_fs_learn.c.

References worksp::acol, bcsol(), count_nnz(), find_topk(), and ctrl_t::k.

Referenced by slim_learn().

{
int nnz = *(A->colptr + A->ncols);
int * acol = Wrk->acol;
/* count nnz */
int kk = count_nnz(w, A->ncols);
/* find topk nnz */
int topk = 0;
/* find the indices of topk entries, meanwhile w is over-written as the topk locations */
find_topk(w, A->ncols, gk_min(ctrl->k, kk), w, &topk);
/* back up original values, this is done only once */
if (*A_colval == NULL){
*A_colval = gk_malloc(sizeof(float)*nnz, "malloc *A_colval");
memcpy((void *)*A_colval, (void *)A->colval, sizeof(float)*nnz);
}
/* remove all A nnz values, this will not affect the column under consideration */
gk_fset(nnz, 0, A->colval);
/* set all columns as inactive */
gk_iset(A->ncols, 0, acol);
/* recover all topk columns in A */
for (int i = 0; i < topk; i ++){
int j = (int)w[i];
/* activate this column */
acol[j] = 1;
int nj = A->colptr[j+1] - A->colptr[j];
for (int k = 0; k < nj; k ++){
/* get the orignal values back */
*(A->colptr[j] + k + A->colval) = *(A->colptr[j] + k + *A_colval);
}
}
/* BCLS */
gk_dset(A->ncols, 0, w);
bcsol(ctrl, A, b, w, Wrk, bl, bu, beta, c);
/* recover full A, specific to binary A, this will over-write the column of b,
but will not matter */
memcpy((void *)A->colval, (void *)*A_colval, sizeof(float)*nnz);
/* activate all columns */
gk_iset(A->ncols, 1, acol);
}
void slim_learn ( ctrl_t ctrl,
gk_csr_t *  train 
)

SLIM learning.

This routine contains the learning algorithm for SLIM

Parameters
[in]ctrlA ctrl structure which contains all the parameters for SLIM learning
[in]trainThe training data

Definition at line 22 of file slim_learn.c.

References worksp::A, worksp::acol, bcsol(), ctrl_t::beta, ctrl_t::bl, ctrl_t::bsize, ctrl_t::bu, csr_Write(), display_timer(), end_timer(), ctrl_t::endi, EPSILON, ctrl_t::fs, ctrl_t::fs_file, get_column(), cs_sparse::i, ctrl_t::lambda, cs_sparse::m, ctrl_t::max_bcls_niters, worksp::max_bcls_niters, ctrl_t::model_file, cs_sparse::n, cs_sparse::nz, cs_sparse::nzmax, cs_sparse::p, read_constraint(), slim_fs_learn(), start_timer(), ctrl_t::starti, and cs_sparse::x.

Referenced by main().

{
/* set up timers */
ctimer_t * timer = gk_malloc(sizeof(ctimer_t), "malloc timer");
ctimer_t * timer0 = gk_malloc(sizeof(ctimer_t), "malloc timer");
start_timer(timer0);
/* constants used across all problems */
int nr = train->nrows;
int ni = train->ncols;
/* lower/upper bound */
double * bl = gk_malloc(sizeof(double)*ni, "malloc bl");
gk_dset(ni, ctrl->bl, bl);
double * bu = gk_malloc(sizeof(double)*ni, "malloc bu");
gk_dset(ni, ctrl->bu, bu);
/* RHS vector for all problems */
double * b = gk_malloc(sizeof(double)*nr, "malloc b");
gk_dset(nr, 0, b);
/* c, linear vector */
double * c = gk_malloc(sizeof(double)*ni, "malloc c");
gk_dset(ni, ctrl->lambda, c);
/* solution vector */
double * w = gk_malloc(sizeof(double)*ni, "malloc w");
gk_dset(ni, 0, w);
/* the A matrix */
gk_csr_t * A = train;
cs * csA = gk_malloc(sizeof(cs), "malloc csA");
/* Workspace for BCLS */
worksp * Wrk = gk_malloc(sizeof(worksp), "malloc Wrk");
Wrk->A = csA;
csA->p = A->colptr;
csA->i = A->colind;
csA->x = A->colval;
csA->m = A->nrows;
csA->n = A->ncols;
csA->nzmax = *(A->rowptr + A->nrows);
csA->nz = -1; /* column-view */
Wrk->acol = gk_malloc(sizeof(int)*ni, "malloc acol");
gk_iset(ni, 1, Wrk->acol);
/* temporary space for a column */
float * A_colval = NULL;
/* output data */
int bsize = ctrl->bsize; /* output block size */
gk_csr_t * mat = gk_csr_Create();
mat->nrows = 0;
mat->ncols = train->ncols;
mat->rowptr = gk_malloc(sizeof(int)*(ni+1), "malloc mat->rowptr");
mat->rowptr[0] = 0;
mat->rowind = gk_malloc(sizeof(int)*ni*bsize, "malloc mat->rowind");
gk_iset(ni*bsize, 0, mat->rowind);
mat->rowval = gk_malloc(sizeof(float)*ni*bsize, "malloc mat->rowval");
gk_fset(ni*bsize, 0, mat->rowval);
/* constraint data */
gk_csr_t * constraint = NULL;
if (ctrl->fs){
constraint = read_constraint(ctrl, ctrl->fs_file);
}
/* starting and ending columns */
int starti = (ctrl->starti >= 0)? ctrl->starti:0;
int endi = (ctrl->endi >= 0)? ctrl->endi:ni;
/* go through all columns */
for (int i = starti; i < endi; i ++){
start_timer(timer);
printf("column %8d: ", i);
/* the index is beyond the true boundary; this may happen due to cold start */
if (i >= train->ncols){
*(mat->rowptr + mat->nrows + 1) = *(mat->rowptr + mat->nrows);
mat->nrows ++;
end_timer(timer);
display_timer(timer, "empty iter ");
continue;
}
/* this column is totally empty */
if (train->colptr[i+1] - train->colptr[i] == 0){
*(mat->rowptr + mat->nrows + 1) = *(mat->rowptr + mat->nrows);
mat->nrows ++;
end_timer(timer);
display_timer(timer, "empty iter ");
continue;
}
/* in case in csr format, there are 0s recored */
int allzeros = 1;
for (int j = train->colptr[i]; j < train->colptr[i+1]; j ++){
if (train->colval[j] != 0) {
allzeros = 0; break;
}
}
if (allzeros == 1){
*(mat->rowptr + mat->nrows + 1) = *(mat->rowptr + mat->nrows);
mat->nrows ++;
end_timer(timer);
display_timer(timer, "empty iter ");
continue;
}
/**********************************************************/
/* BCLS learning */
/**********************************************************/
/* get the i-th column from A */
gk_dset(nr, 0, b);
get_column(A, i, b);
/* /\* 0 <= w[i] <= 0 => w[i] = 0 *\/ */
/* bu[i] = 0; */
gk_dset(ni, 0, w);
/* disable */
Wrk->acol[i] = 0;
if (!ctrl->fs){
bcsol(ctrl, A, b, w, Wrk, bl, bu, ctrl->beta, c);
}
else{
get_column(constraint, i, w);
slim_fs_learn(ctrl, A, b, w, &A_colval, Wrk, bl, bu, ctrl->beta, c);
}
/* timing for this run */
end_timer(timer);
display_timer(timer, "iter ");
/**********************************************************/
/* dump the data */
/**********************************************************/
/* many enough, dump the data */
if (mat->nrows >= ctrl->bsize){
printf("Dumping data...\n");
csr_Write(mat, ctrl->model_file, "a", GK_CSR_FMT_CSR, 1, 1);
mat->nrows = 0;
}
/* fill out the matrix */
*(mat->rowptr + mat->nrows + 1) = *(mat->rowptr + mat->nrows);
for (int j = 0, k = 0; j < ni; j ++){
if (w[j] > EPSILON){
*(mat->rowind + mat->rowptr[mat->nrows] + k) = j;
*(mat->rowval + mat->rowptr[mat->nrows] + k) = w[j];
(*(mat->rowptr + mat->nrows + 1)) ++;
k ++;
}
}
mat->nrows ++;
/* reset for the next run */
Wrk->acol[i] = 1;
/* bu[i] = ctrl->bu; */
} /* end of starti - endi */
end_timer(timer0);
display_timer(timer0, "BCLS");
/* left-over data dump */
printf("Dumping data...\n");
csr_Write(mat, ctrl->model_file, "a", GK_CSR_FMT_CSR, 1, 1);
/* finish up */
gk_free((void **)&timer, LTERM); gk_free((void **)&timer0, LTERM);
gk_csr_Free(&mat); gk_free((void **)&w, LTERM);
gk_free((void **)&bl, &bu, &b, &c, LTERM);
gk_csr_Free(&constraint);
gk_free((void **)&csA, LTERM);
gk_free((void **)&Wrk->acol, LTERM); gk_free((void **)&Wrk, LTERM);
gk_free((void **)&A_colval, LTERM);
}
void slim_predict ( ctrl_t ctrl,
gk_csr_t *  train,
gk_csr_t *  test,
gk_csr_t *  model 
)

SLIM testing.

This routine contains the testing method for SLIM

Parameters
[in]ctrlA ctrl structure which contains all the Parameters for SLIM testing
[in]trainThe training data, which has been used to learn the model
[in]testThe testing data
[in]modelThe model

Definition at line 26 of file slim_predict.c.

References ctrl_t::nratings, and slim_test().

Referenced by main().

{
printf("model->nrows = %d, model->ncols = %d\n", model->nrows, model->ncols);
/* sanity check */
model->ncols = model->nrows;
gk_csr_CreateIndex(model, GK_CSR_COL);
double * eval = slim_test(ctrl, model, train, test);
/* print the results */
for (int j = 0; j < ctrl->nratings; j ++)
printf("For rating value %3d HR = %.5f ARHR = %.5f cumulative HR = %.5f ARHR = %.5f\n",
j+1, eval[j*4], eval[j*4+1], eval[j*4+2], eval[j*4+3]);
/* clean up */
gk_free((void **)&eval, LTERM);
}
double* slim_test ( ctrl_t ctrl,
gk_csr_t *  model,
gk_csr_t *  train,
gk_csr_t *  test 
)

Top-N recommendations and evaluations.

Parameters
[in]ctrlA ctrl structure
[in]modelA model
[in]trainThe training data from which the model is learned
[in]testThe testing data
Returns
eval A set of evaluations

Definition at line 60 of file slim_predict.c.

References ctrl_t::dbglvl, display_timer(), end_timer(), ctrl_t::nratings, ctrl_t::pred_file, start_timer(), and suggest_predict().

Referenced by slim_predict().

{
int nu = test->nrows;
int nhits = 0;
double arh = 0;
int n = 0;
ctimer_t * timer = gk_malloc(sizeof(ctimer_t), "malloc timer");
start_timer(timer);
/* evaluation results for return */
double * eval = gk_malloc(sizeof(double)*(ctrl->nratings)*4, "malloc eval");
gk_dset(ctrl->nratings*4, 0, eval);
/* number of testing instances for each rating value */
int * nr = gk_malloc(sizeof(int)*ctrl->nratings, "malloc nr");
gk_iset(ctrl->nratings, 0, nr);
int ncols = gk_max(train->ncols, model->ncols);
int * nc = gk_malloc(sizeof(int)*ncols, "malloc nc");
gk_iset(ncols, 0, nc);
int * nhc = gk_malloc(sizeof(int)*ncols, "malloc nhc");
gk_iset(ncols, 0, nhc);
/* auxiliary_space */
int * iidx = NULL;
/* output file for predictions */
FILE * pfile = NULL;
if (ctrl->pred_file){
pfile = gk_fopen(ctrl->pred_file, "w", "pred file");
printf("Output predictions to %s file...\n", ctrl->pred_file);
}
/* predictions for all the users */
for (int u = 0; u < nu; u ++){
/* show the process */
if (u % 1000 == 0) {
if (ctrl->dbglvl == 0){
printf("."); fflush(stdout);
}
}
/* no testing instances for this user */
if (test->rowptr[u+1] - test->rowptr[u] == 0) {
if (ctrl->pred_file)
fprintf(pfile, "\n");
continue;
}
n ++;
/* top-n recommendation */
gk_dkv_t * rcmd = NULL;
int nrcmd = 0;
nrcmd = suggest_predict(ctrl, model, &iidx, train, u, &rcmd);
/* stats for the recommendation */
for (int kk = test->rowptr[u]; kk < test->rowptr[u+1]; kk ++){
int r = (int)(test->rowval[kk]); /* assume all ratings are integers [1, 2, ..., nratings] */
nr[r-1] ++ ;
nc[test->rowind[kk]] ++;
}
/* evaluations */
for (int jj = 0; jj < nrcmd; jj ++){
/* output the predictions */
if (ctrl->pred_file)
fprintf(pfile, "%d %.5f ", (int)rcmd[jj].val+1, rcmd[jj].key);
for (int kk = test->rowptr[u]; kk < test->rowptr[u+1]; kk ++){
int r = (int)(test->rowval[kk]); /* assume all ratings are integers [1, 2, ..., nratings] */
/* hit hit */
if (rcmd[jj].val == test->rowind[kk]){
nhc[test->rowind[kk]] ++;
/* overall hit rates */
nhits ++; arh += 1.0/(double)(jj + 1) ;
/* hit rates on different ratings */
eval[(r - 1)*4 + 0] += 1.0; /* hit rate on rating r */
eval[(r - 1)*4 + 1] += 1.0/(double)(jj + 1) ; /* arh on rating r */
eval[(r - 1)*4 + 2] = eval[(r - 1)*4 + 0];
eval[(r - 1)*4 + 3] = eval[(r - 1)*4 + 1];
}
}
}
/* finalize the prediction output */
if (ctrl->pred_file)
fprintf(pfile, "\n");
/* clean up */
gk_free((void **)&rcmd, LTERM);
}
/* end timing */
printf("\n");
end_timer(timer);
display_timer(timer, "SLIM prediction");
/* all stats */
for (int i = 0; i < ctrl->nratings; i ++){
if (nr[i] > 0){
eval[i*4 + 0] /= (double)nr[i];
eval[i*4 + 1] /= (double)nr[i];
}
}
/* cumulative stats */
for (int i = ctrl->nratings - 2; i >= 0; i --){
nr[i] += nr[i+1]; /* cumulative counts */
eval[i*4 + 2] += eval[(i+1)*4 + 2]; /* cumulative hit counts */
eval[i*4 + 3] += eval[(i+1)*4 + 3]; /* cumulative rhr counts */
}
for (int i = 0; i < ctrl->nratings; i ++){
if (nr[i] > 0){
eval[i*4 + 2] /= (double)nr[i];
eval[i*4 + 3] /= (double)nr[i];
}
}
/* finish up */
if (ctrl->pred_file)
gk_fclose(pfile);
gk_free((void **)&nc, LTERM);
gk_free((void **)&nhc, LTERM);
gk_free((void **)&nr, LTERM);
gk_free((void **)&timer, LTERM);
gk_free((void **)&iidx, LTERM);
return eval;
}
void start_timer ( ctimer_t ctimer)

Start a timer to record current time.

Parameters
[in]ctimerA timer to start

Definition at line 88 of file util.c.

References ctimer_t::start.

Referenced by slim_learn(), and slim_test().

{
ctimer->start = clock();
}
int suggest_predict ( ctrl_t ctrl,
gk_csr_t *  model,
int **  iidx,
gk_csr_t *  train,
int  u,
gk_dkv_t **  rcmd 
)

Top-N recommendation for a user.

Parameters
[in]ctrlA ctrl structure
[in]modelA model
[in]iidxAn auxiliary array for efficient recommendations
[in]trainTraining data from which the model is learned
[in]uThe index of the user for which the top-n recommendations are generated
[out]rcmdThe list of recommendations, in which the keys are the recommendation scores and the values are the item indices
Returns
int The actual number of recommendations

Definition at line 228 of file slim_predict.c.

References ctrl_t::topn.

Referenced by slim_test().

{
if (model->colptr == NULL)
gk_csr_CreateIndex(model, GK_CSR_COL);
int ni = train->ncols;
if (*iidx == NULL)
*iidx = gk_malloc(sizeof(int)*ni, "malloc *iidx");
gk_iset(ni, -1, *iidx);
int nuitrn = train->rowptr[u+1] - train->rowptr[u];
/* special case when no training data, thus no recommendations */
if (nuitrn == 0){
*rcmd = NULL;
return 0;
}
for (int ii = 0; ii < nuitrn; ii ++)
*(*iidx + *(train->rowptr[u] + ii + train->rowind)) -= 1;
gk_dkv_t * ccandb = gk_malloc(sizeof(gk_dkv_t)*ni, "malloc ccandb");
int nrcmd = 0;
/* efficient recommendations */
nuitrn = train->rowptr[u+1] - train->rowptr[u];
for (int i = 0; i < nuitrn; i ++){
int ii = *(train->rowptr[u] + i + train->rowind);
for (int j = 0; j < model->colptr[ii+1] - model->colptr[ii]; j ++){
int jj = *(model->colptr[ii] + j + model->colind);
if ((*iidx)[jj] < -1) continue;
if ((*iidx)[jj] == -1){
(*iidx)[jj] = nrcmd;
ccandb[nrcmd].key = *(model->colptr[ii] + j + model->colval) * 1.0;
ccandb[nrcmd].val = jj;
nrcmd ++;
}else{
ccandb[(*iidx)[jj]].key += *(model->colptr[ii] + j + model->colval) * 1.0;
}
}
}
/* sorting */
gk_dkvsortd(nrcmd, ccandb);
int nrcmd2 = gk_min(nrcmd, ctrl->topn);
*rcmd = ccandb;
return nrcmd2;
}