void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { if (nargout > 1 || nargin < 2 || nargin > 4) { mexErrMsgTxt ("Usage: C = cs_add(A,B,alpha,beta)") ; } if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1]) || (nargin > 2 && mxIsComplex (pargin [2])) || (nargin > 3 && mxIsComplex (pargin [3]))) { #ifndef NCOMPLEX cs_complex_t alpha, beta ; cs_cl Amatrix, Bmatrix, *A, *B, *C, *D ; A = cs_cl_mex_get_sparse (&Amatrix, 0, pargin [0]) ; /* get A */ B = cs_cl_mex_get_sparse (&Bmatrix, 0, pargin [1]) ; /* get B */ alpha = (nargin < 3) ? 1 : get_complex (pargin [2]) ; /* get alpha */ beta = (nargin < 4) ? 1 : get_complex (pargin [3]) ; /* get beta */ C = cs_cl_add (A,B,alpha,beta) ; /* C = alpha*A + beta *B */ cs_cl_dropzeros (C) ; /* drop zeros */ D = cs_cl_transpose (C, 1) ; /* sort result via double transpose */ cs_cl_spfree (C) ; C = cs_cl_transpose (D, 1) ; cs_cl_spfree (D) ; pargout [0] = cs_cl_mex_put_sparse (&C) ; /* return C */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { double alpha, beta ; cs_dl Amatrix, Bmatrix, *A, *B, *C, *D ; A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ B = cs_dl_mex_get_sparse (&Bmatrix, 0, 1, pargin [1]) ; /* get B */ alpha = (nargin < 3) ? 1 : mxGetScalar (pargin [2]) ; /* get alpha */ beta = (nargin < 4) ? 1 : mxGetScalar (pargin [3]) ; /* get beta */ C = cs_dl_add (A,B,alpha,beta) ; /* C = alpha*A + beta *B */ cs_dl_dropzeros (C) ; /* drop zeros */ D = cs_dl_transpose (C, 1) ; /* sort result via double transpose */ cs_dl_spfree (C) ; C = cs_dl_transpose (D, 1) ; cs_dl_spfree (D) ; pargout [0] = cs_dl_mex_put_sparse (&C) ; /* return C */ } }
void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { cs_dl *A, Amatrix ; double *x ; CS_INT i, m, n, *parent, *post, *rowcount ; if (nargout > 1 || nargin != 3) { mexErrMsgTxt ("Usage: r = cs_rowcnt(A,parent,post)") ; } /* get inputs */ A = cs_dl_mex_get_sparse (&Amatrix, 1, 0, pargin [0]) ; n = A->n ; parent = cs_dl_mex_get_int (n, pargin [1], &i, 0) ; post = cs_dl_mex_get_int (n, pargin [2], &i, 1) ; rowcount = rowcnt (A, parent, post) ; pargout [0] = mxCreateDoubleMatrix (1, n, mxREAL) ; x = mxGetPr (pargout [0]) ; for (i = 0 ; i < n ; i++) x [i] = rowcount [i] ; cs_dl_free (rowcount) ; }
/* C = cs_transpose (A), computes C=A', where A must be sparse. C = cs_transpose (A,kind) computes C=A.' if kind <= 0, C=A' if kind > 0 */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT values ; if (nargout > 1 || nargin < 1 || nargin > 2) { mexErrMsgTxt ("Usage: C = cs_transpose(A,kind)") ; } values = (nargin > 1) ? mxGetScalar (pargin [1]) : 1 ; values = (values <= 0) ? -1 : 1 ; if (mxIsComplex (pargin [0])) { #ifndef NCOMPLEX cs_cl Amatrix, *A, *C ; A = cs_cl_mex_get_sparse (&Amatrix, 0, pargin [0]) ; /* get A */ C = cs_cl_transpose (A, values) ; /* C = A' */ pargout [0] = cs_cl_mex_put_sparse (&C) ; /* return C */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl Amatrix, *A, *C ; A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ C = cs_dl_transpose (A, values) ; /* C = A' */ pargout [0] = cs_dl_mex_put_sparse (&C) ; /* return C */ } }
/* cs_lusol: solve A*x=b using a sparse LU factorization */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { double tol ; CS_INT order ; if (nargout > 1 || nargin < 2 || nargin > 4) { mexErrMsgTxt ("Usage: x = cs_lusol(A,b,order,tol)") ; } order = (nargin < 3) ? 2 : mxGetScalar (pargin [2]) ; order = CS_MAX (order, 0) ; order = CS_MIN (order, 3) ; if (nargin == 2) { tol = 1 ; /* normal partial pivoting */ } else if (nargin == 3) { tol = (order == 1) ? 0.001 : 1 ; /* tol = 0.001 for amd(A+A') */ } else { tol = mxGetScalar (pargin [3]) ; } if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl *A, Amatrix ; cs_complex_t *x ; A = cs_cl_mex_get_sparse (&Amatrix, 1, pargin [0]) ; /* get A */ x = cs_cl_mex_get_double (A->n, pargin [1]) ; /* x = b */ if (!cs_cl_lusol (order, A, x, tol)) /* x = A\x */ { mexErrMsgTxt ("failed (singular or out of memory)") ; } cs_cl_free (A->x) ; /* complex copy no longer needed */ pargout [0] = cs_cl_mex_put_double (A->n, x) ; /* return x */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl *A, Amatrix ; double *x, *b ; A = cs_dl_mex_get_sparse (&Amatrix, 1, 1, pargin [0]) ; /* get A */ b = cs_dl_mex_get_double (A->n, pargin [1]) ; /* get b */ x = cs_dl_mex_put_double (A->n, b, &(pargout [0])) ; /* x = b */ if (!cs_dl_lusol (order, A, x, tol)) /* x = A\x */ { mexErrMsgTxt ("failed (singular or out of memory)") ; } } }
/* cs_qrsol: solve least squares or underdetermined problem */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT k, order ; if (nargout > 1 || nargin < 2 || nargin > 3) { mexErrMsgTxt ("Usage: x = cs_qrsol(A,b,order)") ; } order = (nargin < 3) ? 3 : mxGetScalar (pargin [2]) ; order = CS_MAX (order, 0) ; order = CS_MIN (order, 3) ; if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl *A, Amatrix ; cs_complex_t *x, *b ; A = cs_cl_mex_get_sparse (&Amatrix, 0, pargin [0]) ; /* get A */ b = cs_cl_mex_get_double (A->m, pargin [1]) ; /* get b */ x = cs_dl_calloc (CS_MAX (A->m, A->n), sizeof (cs_complex_t)) ; for (k = 0 ; k < A->m ; k++) x [k] = b [k] ; /* x = b */ cs_free (b) ; if (!cs_cl_qrsol (order, A, x)) /* x = A\x */ { mexErrMsgTxt ("QR solve failed") ; } pargout [0] = cs_cl_mex_put_double (A->n, x) ; /* return x */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl *A, Amatrix ; double *x, *b ; A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ b = cs_dl_mex_get_double (A->m, pargin [1]) ; /* get b */ x = cs_dl_calloc (CS_MAX (A->m, A->n), sizeof (double)) ; /* x = b */ for (k = 0 ; k < A->m ; k++) x [k] = b [k] ; if (!cs_dl_qrsol (order, A, x)) /* x = A\x */ { mexErrMsgTxt ("QR solve failed") ; } cs_dl_mex_put_double (A->n, x, &(pargout [0])) ; /* return x */ cs_free (x) ; } }
/* cs_sqr: symbolic sparse QR factorization */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { double s ; cs_dls *S ; cs_dl Amatrix, *A ; CS_INT m, n, order, *p ; if (nargout > 7 || nargin != 1) { mexErrMsgTxt ("Usage: [vnz,rnz,parent,c,leftmost,p,q] = cs_sqr(A)") ; } A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ m = A->m ; n = A->n ; if (m < n) mexErrMsgTxt ("A must have # rows >= # columns") ; order = (nargout == 7) ? 3 : 0 ; /* determine ordering */ S = cs_dl_sqr (order, A, 1) ; /* symbolic QR ordering & analysis*/ if (!S) mexErrMsgTxt ("cs_sqr failed") ; s = S->lnz ; cs_dl_mex_put_double (1, &s, &(pargout [0])) ; /* return nnz(V) */ s = S->unz ; cs_dl_mex_put_double (1, &s, &(pargout [1])) ; /* return nnz(R) */ pargout [2] = cs_dl_mex_put_int (S->parent, n, 1, 0) ; /* return parent */ pargout [3] = cs_dl_mex_put_int (S->cp, n, 0, 0) ; /* return c */ pargout [4] = cs_dl_mex_put_int (S->leftmost, m, 1, 0) ;/* return leftmost*/ p = cs_dl_pinv (S->pinv, S->m2) ; /* p = pinv' */ pargout [5] = cs_dl_mex_put_int (p, S->m2, 1, 1) ; /* return p */ if (nargout > 6) { pargout [6] = cs_dl_mex_put_int (S->q, n, 1, 0) ; /* return q */ } cs_dl_sfree (S) ; }
/* cs_updown: sparse Cholesky update/downdate (rank-1 or multiple rank) */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT ignore, j, k, n, lnz, *parent, sigma = 1, cp [2], ok ; char sigma_string [20] ; if (nargout > 1 || nargin < 3 || nargin > 4) { mexErrMsgTxt ("Usage: L = cs_updown(L,C,parent,sigma)") ; } if (nargin > 3 && mxIsChar (pargin [3])) { mxGetString (pargin [3], sigma_string, 8) ; sigma = (sigma_string [0] == '-') ? (-1) : 1 ; } n = mxGetN (pargin [0]) ; parent = cs_dl_mex_get_int (n, pargin [2], &ignore, 0) ; /* get parent*/ if (mxIsComplex (pargin [0]) || mxIsComplex (pargin [1])) { #ifndef NCOMPLEX cs_cl Lmatrix, *Lin, Cmatrix, *C, *L, Cvector, *Cvec ; /* get input L, and copy MATLAB complex to C complex type */ Lin = cs_cl_mex_get_sparse (&Lmatrix, 1, pargin [0]) ; /* make a copy of L (this can take more work than updating L itself) */ lnz = Lin->p [n] ; L = cs_cl_spalloc (n, n, lnz, 0, 0) ; for (j = 0 ; j <= n ; j++) L->p [j] = Lin->p [j] ; for (k = 0 ; k < lnz ; k++) L->i [k] = Lin->i [k] ; /* complex values already copied into Lin->x, use shallow copy for L */ L->x = Lin->x ; cs_mex_check (0, n, -1, 0, 1, 1, pargin [1]) ; /* get C */ C = cs_cl_mex_get_sparse (&Cmatrix, 0, pargin [1]) ; /* do the update one column at a time */ Cvec = &Cvector ; Cvec->m = n ; Cvec->n = 1 ; Cvec->p = cp ; Cvec->nz = -1 ; cp [0] = 0 ; for (k = 0 ; k < C->n ; k++) { /* extract C(:,k) */ cp [1] = C->p [k+1] - C->p [k] ; Cvec->nzmax = cp [1] ; Cvec->i = C->i + C->p [k] ; Cvec->x = C->x + C->p [k] ; /* update/downdate */ ok = cs_cl_updown (L, sigma, Cvec, parent) ; if (!ok) mexErrMsgTxt ("matrix is not positive definite") ; } /* return new L */ pargout [0] = cs_cl_mex_put_sparse (&L) ; cs_free (C->x) ; /* free complex copy of C */ #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dl Lmatrix, *Lin, Cmatrix, *C, *L, Cvector, *Cvec ; /* get input L */ Lin = cs_dl_mex_get_sparse (&Lmatrix, 1, 1, pargin [0]) ; /* make a copy of L (this can take more work than updating L itself) */ lnz = Lin->p [n] ; L = cs_dl_spalloc (n, n, lnz, 1, 0) ; for (j = 0 ; j <= n ; j++) L->p [j] = Lin->p [j] ; for (k = 0 ; k < lnz ; k++) L->i [k] = Lin->i [k] ; for (k = 0 ; k < lnz ; k++) L->x [k] = Lin->x [k] ; cs_mex_check (0, n, -1, 0, 1, 1, pargin [1]) ; /* get C */ C = cs_dl_mex_get_sparse (&Cmatrix, 0, 1, pargin [1]) ; /* do the update one column at a time */ Cvec = &Cvector ; Cvec->m = n ; Cvec->n = 1 ; Cvec->p = cp ; Cvec->nz = -1 ; cp [0] = 0 ; for (k = 0 ; k < C->n ; k++) { /* extract C(:,k) */ cp [1] = C->p [k+1] - C->p [k] ; Cvec->nzmax = cp [1] ; Cvec->i = C->i + C->p [k] ; Cvec->x = C->x + C->p [k] ; /* update/downdate */ ok = cs_dl_updown (L, sigma, Cvec, parent) ; if (!ok) mexErrMsgTxt ("matrix is not positive definite") ; } /* return new L */ pargout [0] = cs_dl_mex_put_sparse (&L) ; } }
/* [C, [E]] = provaKoren (A,B), computes Corr(A,B), where A and B must be sparse. [C, [E]] = provaKoren (A,B,mode) computes Corr(A,b). If mode=0, the column average is calculated on common elements, otherwise column average is calculated on all non-zeros elements (DEFAULT) E is a matrix contaninng the number of common elements */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT modeAllElement ; if (nargout > 2 || nargin < 2 || nargin > 3) { mexErrMsgTxt ("Usage: [C, [E]] = provaKoren (A,B,[mode=0])") ; } modeAllElement = (nargin > 2) ? mxGetScalar (pargin [2]) : 1 ; /* default = 1 */ modeAllElement = (modeAllElement == 0) ? 0 : 1 ; if (modeAllElement && log) fprintf(stdout,"average computed on all non-zeros elements\n"); cs_dl Amatrix, Bmatrix, *A, *B, *C; A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ B = cs_dl_mex_get_sparse (&Bmatrix, 0, 1, pargin [1]) ; /* get B */ UF_long i, p, pp, Am, An, Anzmax, Anz, *Ap, *Ai ; UF_long j, q, qq, Bm, Bn, Bnzmax, Bnz, *Bp, *Bi ; double *Ax, *Bx; if (!A || !B) { if (log) printf ("(null)\n") ; return ; } Am = A->m ; An = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ; Anzmax = A->nzmax ; Anz = A->nz ; Bm = B->m ; Bn = B->n ; Bp = B->p ; Bi = B->i ; Bx = B->x ; Bnzmax = B->nzmax ; Bnz = B->nz ; if (log) fprintf(stdout,"A: mxn = %dx%d\n",Am,An); if (log) fprintf(stdout,"B: mxn = %dx%d\n",Bm,Bn); /* allocate result */ cs *corrMatrix = cs_spalloc (An, Bn, An*Bn, 1, 1) ; cs *commonElementMatrix = cs_spalloc (An, Bn, An*Bn, 1, 1) ; for (i = 0 ; i < An ; i++) { for (j = 0 ; j < Bn ; j++) { p=Ap[i]; q=Bp[j]; pp = Ap[i+1]; qq = Bp[j+1]; /* mean on common elements*/ double meanA=0, meanB=0; long countElementsA=0, countElementsB=0; if (modeAllElement) { for (p=Ap[i] ; p<pp ; p++) { meanA += Ax[p]; countElementsA++; } for (q=Bp[j] ; q<qq ; q++) { meanB += Bx[q]; countElementsB++; } } else { while (pp && qq && p<pp && q<qq) { /* fprintf(stdout,"i=%d, j=%d, p=%d, q=%d, pp=%d, qq=%d, rowA=%d, rowB=%d \n",i,j,p,q,pp,qq,Ai[p],Bi[q]); */ if (Ai[p]==Bi[q]) { meanA += Ax[p]; meanB += Bx[q]; countElementsA++; countElementsB++; /* fprintf(stdout,"(%d,%d) - sum A = %f, sum B = %f \n",Ai[p],Bi[q],meanA,meanB); */ p++; q++; /* values Ax[p] and Bx[q] referring to the same row */ } else if (Ai[p]>Bi[q]) { q++; } else { p++; } } } meanA = meanA / ((double)countElementsA); meanB = meanB / ((double)countElementsB); /* fprintf(stdout,"common elements = %d - mean A = %f, mean B = %f \n",countCommonElements,meanA,meanB); */ /* correleation on common elements*/ double corr; double corrNum=0, corrDenA=0, corrDenB=0; double entryA, entryB; p=Ap[i]; q=Bp[j]; pp = Ap[i+1]; qq = Bp[j+1]; long countCommonElements=0; while (pp && qq && p<pp && q<qq) { /* fprintf(stdout,"i=%d, j=%d, p=%d, q=%d, pp=%d, qq=%d, rowA=%d, rowB=%d \n",i,j,p,q,pp,qq,Ai[p],Bi[q]); */ if (Ai[p]==Bi[q]) { entryA=Ax[p]-meanA; entryB=Bx[q]-meanB; corrNum += entryA * entryB; corrDenA += entryA*entryA; corrDenB += entryB*entryB; p++; q++; countCommonElements++; /* values Ax[p] and Bx[q] referring to the same row */ } else if (Ai[p]>Bi[q]) { q++; } else { p++; } } /* fprintf(stdout,"corrNum=%f, corrDenA=%f, corrDenB=%f\n",corrNum,corrDenA,corrDenB); */ corrDenA = (corrDenA==0) ? 1 : corrDenA; corrDenB = (corrDenB==0) ? 1 : corrDenB; corr = corrNum / (sqrt(corrDenA*corrDenB)); /* fprintf(stdout,"corr(%d,%d)=%f\n",i,j,corr); */ cs_entry(corrMatrix,i,j,corr); cs_entry(commonElementMatrix,i,j,countCommonElements); } } if (log) fprintf(stdout,"provaKoren: outputing computed matrices \n"); corrMatrix=cs_compress(corrMatrix); pargout [0] = cs_dl_mex_put_sparse (&corrMatrix) ; /* return C */ if (nargout>1) { commonElementMatrix=cs_compress(commonElementMatrix); pargout [1] = cs_dl_mex_put_sparse (&commonElementMatrix) ; /* return E */ } }
/* cs_lu: sparse LU factorization, with optional fill-reducing ordering */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT n, order, *p ; double tol ; if (nargout > 4 || nargin > 3 || nargin < 1) { mexErrMsgTxt ("Usage: [L,U,p,q] = cs_lu (A,tol)") ; } if (nargin == 2) /* determine tol and ordering */ { tol = mxGetScalar (pargin [1]) ; order = (nargout == 4) ? 1 : 0 ; /* amd (A+A'), or natural */ } else { tol = 1 ; order = (nargout == 4) ? 2 : 0 ; /* amd(S'*S) w/dense rows or I */ } if (mxIsComplex (pargin [0])) { #ifndef NCOMPLEX cs_cls *S ; cs_cln *N ; cs_cl Amatrix, *A, *D ; A = cs_cl_mex_get_sparse (&Amatrix, 1, pargin [0]) ; /* get A */ n = A->n ; S = cs_cl_sqr (order, A, 0) ; /* symbolic ordering, no QR bound */ N = cs_cl_lu (A, S, tol) ; /* numeric factorization */ if (!N) mexErrMsgTxt ("cs_lu failed (singular, or out of memory)") ; cs_cl_free (A->x) ; /* complex copy no longer needed */ cs_cl_dropzeros (N->L) ; /* drop zeros from L and sort it */ D = cs_cl_transpose (N->L, 1) ; cs_cl_spfree (N->L) ; N->L = cs_cl_transpose (D, 1) ; cs_cl_spfree (D) ; cs_cl_dropzeros (N->U) ; /* drop zeros from U and sort it */ D = cs_cl_transpose (N->U, 1) ; cs_cl_spfree (N->U) ; N->U = cs_cl_transpose (D, 1) ; cs_cl_spfree (D) ; p = cs_cl_pinv (N->pinv, n) ; /* p=pinv' */ pargout [0] = cs_cl_mex_put_sparse (&(N->L)) ; /* return L */ pargout [1] = cs_cl_mex_put_sparse (&(N->U)) ; /* return U */ pargout [2] = cs_dl_mex_put_int (p, n, 1, 1) ; /* return p */ /* return Q */ if (nargout == 4) pargout [3] = cs_dl_mex_put_int (S->q, n, 1, 0) ; cs_cl_nfree (N) ; cs_cl_sfree (S) ; #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dls *S ; cs_dln *N ; cs_dl Amatrix, *A, *D ; A = cs_dl_mex_get_sparse (&Amatrix, 1, 1, pargin [0]) ; /* get A */ n = A->n ; S = cs_dl_sqr (order, A, 0) ; /* symbolic ordering, no QR bound */ N = cs_dl_lu (A, S, tol) ; /* numeric factorization */ if (!N) mexErrMsgTxt ("cs_lu failed (singular, or out of memory)") ; cs_dl_dropzeros (N->L) ; /* drop zeros from L and sort it */ D = cs_dl_transpose (N->L, 1) ; cs_dl_spfree (N->L) ; N->L = cs_dl_transpose (D, 1) ; cs_dl_spfree (D) ; cs_dl_dropzeros (N->U) ; /* drop zeros from U and sort it */ D = cs_dl_transpose (N->U, 1) ; cs_dl_spfree (N->U) ; N->U = cs_dl_transpose (D, 1) ; cs_dl_spfree (D) ; p = cs_dl_pinv (N->pinv, n) ; /* p=pinv' */ pargout [0] = cs_dl_mex_put_sparse (&(N->L)) ; /* return L */ pargout [1] = cs_dl_mex_put_sparse (&(N->U)) ; /* return U */ pargout [2] = cs_dl_mex_put_int (p, n, 1, 1) ; /* return p */ /* return Q */ if (nargout == 4) pargout [3] = cs_dl_mex_put_int (S->q, n, 1, 0) ; cs_dl_nfree (N) ; cs_dl_sfree (S) ; } }
/* cs_qr: sparse QR factorization */ void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { CS_INT m, n, order, *p ; if (nargout > 5 || nargin != 1) { mexErrMsgTxt ("Usage: [V,beta,p,R,q] = cs_qr(A)") ; } order = (nargout == 5) ? 3 : 0 ; /* determine ordering */ m = mxGetM (pargin [0]) ; n = mxGetN (pargin [0]) ; if (m < n) mexErrMsgTxt ("A must have # rows >= # columns") ; if (mxIsComplex (pargin [0])) { #ifndef NCOMPLEX cs_cls *S ; cs_cln *N ; cs_cl Amatrix, *A, *D ; A = cs_cl_mex_get_sparse (&Amatrix, 0, pargin [0]) ; /* get A */ S = cs_cl_sqr (order, A, 1) ; /* symbolic QR ordering & analysis*/ N = cs_cl_qr (A, S) ; /* numeric QR factorization */ cs_free (A->x) ; if (!N) mexErrMsgTxt ("qr failed") ; cs_cl_dropzeros (N->L) ; /* drop zeros from V and sort */ D = cs_cl_transpose (N->L, 1) ; cs_cl_spfree (N->L) ; N->L = cs_cl_transpose (D, 1) ; cs_cl_spfree (D) ; cs_cl_dropzeros (N->U) ; /* drop zeros from R and sort */ D = cs_cl_transpose (N->U, 1) ; cs_cl_spfree (N->U) ; N->U = cs_cl_transpose (D, 1) ; cs_cl_spfree (D) ; m = N->L->m ; /* m may be larger now */ p = cs_cl_pinv (S->pinv, m) ; /* p = pinv' */ pargout [0] = cs_cl_mex_put_sparse (&(N->L)) ; /* return V */ cs_dl_mex_put_double (n, N->B, &(pargout [1])) ; /* return beta */ pargout [2] = cs_dl_mex_put_int (p, m, 1, 1) ; /* return p */ pargout [3] = cs_cl_mex_put_sparse (&(N->U)) ; /* return R */ pargout [4] = cs_dl_mex_put_int (S->q, n, 1, 0) ; /* return q */ cs_cl_nfree (N) ; cs_cl_sfree (S) ; #else mexErrMsgTxt ("complex matrices not supported") ; #endif } else { cs_dls *S ; cs_dln *N ; cs_dl Amatrix, *A, *D ; A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [0]) ; /* get A */ S = cs_dl_sqr (order, A, 1) ; /* symbolic QR ordering & analysis*/ N = cs_dl_qr (A, S) ; /* numeric QR factorization */ if (!N) mexErrMsgTxt ("qr failed") ; cs_dl_dropzeros (N->L) ; /* drop zeros from V and sort */ D = cs_dl_transpose (N->L, 1) ; cs_dl_spfree (N->L) ; N->L = cs_dl_transpose (D, 1) ; cs_dl_spfree (D) ; cs_dl_dropzeros (N->U) ; /* drop zeros from R and sort */ D = cs_dl_transpose (N->U, 1) ; cs_dl_spfree (N->U) ; N->U = cs_dl_transpose (D, 1) ; cs_dl_spfree (D) ; m = N->L->m ; /* m may be larger now */ p = cs_dl_pinv (S->pinv, m) ; /* p = pinv' */ pargout [0] = cs_dl_mex_put_sparse (&(N->L)) ; /* return V */ cs_dl_mex_put_double (n, N->B, &(pargout [1])) ; /* return beta */ pargout [2] = cs_dl_mex_put_int (p, m, 1, 1) ; /* return p */ pargout [3] = cs_dl_mex_put_sparse (&(N->U)) ; /* return R */ pargout [4] = cs_dl_mex_put_int (S->q, n, 1, 0) ; /* return q */ cs_dl_nfree (N) ; cs_dl_sfree (S) ; } }
void mexFunction ( int nargout, mxArray *pargout [ ], int nargin, const mxArray *pargin [ ] ) { int iterations; double mu, lrate,lrateB, lambda,lambdaB; double *buin, *biin, *qin, *xin, *yin, *pin, *zin; double *bu, *bi, *q, *x, *y, *p, *z; int ls; int itemsNum, usersNum; cs_dl Amatrix, *A; bool useruser = false; FILE *verbose; if (nargout < 5 || nargout > 7 || nargin < 10 || nargin > 12) { mexErrMsgTxt ("Usage: [bu,bi,q,x,y,[p,z]]=learnFactorModel(urm,mu,bu,bi,iterations,lrate,lrateB,lambda,lambdaB,q,x,y,[p,z]) \n urm must be sparse, bu and bi must be dense") ; } if (nargout>5 && nargin>11) { useruser=true; /* enable the integration of the user-user model into the item-item model */ if (log) fprintf(stdout,"user-user model enabled\n"); } int indexArgin = 0, indexArgout = 0;; if (log>1) { verbose = fopen("/home/roby/verbose.txt", "w+"); fprintf(stdout, "verbose mode"); } if (log) fprintf(stdout,"--input started\n"); A = cs_dl_mex_get_sparse (&Amatrix, 0, 1, pargin [indexArgin]) ; usersNum = mxGetM(pargin[indexArgin++]); /* get A=urm */ mu = mxGetScalar (pargin [indexArgin++]); buin = mxGetPr(pargin[indexArgin++]); biin = mxGetPr(pargin[indexArgin++]); iterations = mxGetScalar (pargin [indexArgin++]); lrate = mxGetScalar (pargin [indexArgin++]); lrateB = mxGetScalar (pargin [indexArgin++]); lambda = mxGetScalar (pargin [indexArgin++]); lambdaB = mxGetScalar (pargin [indexArgin++]); qin = mxGetPr(pargin[indexArgin]); ls = mxGetM(pargin[indexArgin]); itemsNum = mxGetN(pargin[indexArgin++]); xin = mxGetPr(pargin[indexArgin++]); yin = mxGetPr(pargin[indexArgin++]); if (useruser) { pin = mxGetPr(pargin[indexArgin++]); zin = mxGetPr(pargin[indexArgin++]); if (log) fprintf(stdout," read: p and z \n"); } if (log) fprintf(stdout,"users=%d, items=%d\n",usersNum,itemsNum); if (log) fprintf(stdout,"number of factors=%d, number of iterations=%d\n",ls,iterations); if (log) fprintf(stdout," bu =[%d x %d] \n", mxGetM(pargin[2]), mxGetN(pargin[2])); if (log) fprintf(stdout," bi =[%d x %d] \n", mxGetM(pargin[3]), mxGetN(pargin[3])); if (log) fprintf(stdout,"--input completed\n"); UF_long Am, An, Anzmax, Anz, *Ap, *Ai ; double *Ax ; if (!A) { printf ("(null)\n") ; return ; } Am = A->m ; An = A->n ; Ap = A->p ; Ai = A->i ; Ax = A->x ; Anzmax = A->nzmax ; Anz = A->nz ; /* B = transpose of URM */ cs_dl *B; UF_long Bm, Bn, Bnzmax, Bnz, *Bp, *Bi ; double *Bx ; B = cs_dl_transpose (A, 1) ; /* B = A' = urm' */ Bm = B->m ; Bn = B->n ; Bp = B->p ; Bi = B->i ; Bx = B->x ; Bnzmax = B->nzmax ; Bnz = B->nz ; int ii; pargout[indexArgout]=mxCreateDoubleMatrix(usersNum,1,mxREAL); bu=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<usersNum;ii++) bu[ii] = buin[ii]; pargout[indexArgout]=mxCreateDoubleMatrix(itemsNum,1,mxREAL); bi=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<itemsNum;ii++) bi[ii] = biin[ii]; pargout[indexArgout]=mxCreateDoubleMatrix(ls,itemsNum,mxREAL); q=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<ls*itemsNum;ii++) q[ii] = qin[ii]; pargout[indexArgout]=mxCreateDoubleMatrix(ls,itemsNum,mxREAL); x=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<ls*itemsNum;ii++) x[ii] = xin[ii]; pargout[indexArgout]=mxCreateDoubleMatrix(ls,itemsNum,mxREAL); y=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<ls*itemsNum;ii++) y[ii] = yin[ii]; if (useruser) { pargout[indexArgout]=mxCreateDoubleMatrix(ls,usersNum,mxREAL); p=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<ls*usersNum;ii++) p[ii] = pin[ii]; if (log) fprintf(stdout," p initialized \n"); pargout[indexArgout]=mxCreateDoubleMatrix(ls,usersNum,mxREAL); z=mxGetPr(pargout[indexArgout++]); for (ii=0;ii<ls*usersNum;ii++) z[ii] = zin[ii]; if (log) fprintf(stdout," z initialized \n"); } if (log) fprintf(stdout," \n allocated %d outputs \n",indexArgout); int count, u, i, j, k; int iii; int itemj; int numRatedItems, numRatingUsers; double puCoeff, zvCoeff; double *pu=calloc(ls, sizeof(double)); double *zv=calloc(ls, sizeof(double)); double sum[ls]; double *sumUU=calloc(ls, sizeof(double)); double cumerror=0.0, pseudoRMSE=0.0; long numTests=0; int anomaliesCounter=0; const int maxAnomalies=100000; time_t t1,t2, t0; (void) time(&t0); for (count=0;count<iterations;count++) /* FOR count=1,#iterations DO */ { (void) time(&t1); cumerror=0.0; numTests = 0; anomaliesCounter = 0; for (u=0;u<usersNum;u++) /* FOR u=1,..,m DO */ { double errorUU=0; for (iii=0;iii<ls;iii++) pu[iii]=0.0; /* pu[ls] <- 0 */ numRatedItems = (int) (Bp [u+1] - Bp [u]); if (numRatedItems==0) continue; /* compute the component independent of i*/ for (j=Bp[u]; j<Bp[u+1]; j++) { double ruj, biasi, xjk, yjk; itemj = Bi[j]; ruj=Bx[j]; /* r_uj */ biasi=bi[itemj]; puCoeff = (ruj - (mu + bu[u] + biasi)) / (sqrt((double) numRatedItems)); /* |R(u)|^-1/2 * (r_uj - b_uj) */ for (k=0;k<ls;k++) /* compute pu for each feature k*/ { xjk = x[ls*itemj+k]; /* x[ls*itemj+k] = x[ls,itemj] */ yjk = y[ls*itemj+k]; /* y[ls*itemj+k] = y[ls,itemj] */ pu[k] = pu[k] + (puCoeff * xjk); pu[k] = pu[k] + (yjk / (sqrt((double) numRatedItems))); } } for (iii=0;iii<ls;iii++) sum[iii]=0.0; /* sum[ls] <- 0 */ if (useruser) { for (iii=0;iii<ls;iii++) sumUU[iii]=0.0; /* sumUU[ls] <- 0 */ } /* FOR ALL i (itemj) IN R(u) DO */ for (j=Bp[u]; j<Bp[u+1]; j++) { double r_hat_ui=0.0, e_ui; double biasi; itemj = Bi[j]; if (useruser) /* if user-user is enabled */ { int useri; numRatingUsers = Ap [itemj+1] - Ap [itemj]; /* |R(i)| */ for (iii=0;iii<ls;iii++) zv[iii]=0.0; /* zv[ls] <- 0 */ biasi = bi[itemj]; /* bias item j */ for (i=Ap[itemj]; i<Ap[itemj+1]; i++) { double rvj, biasvj, zjk; useri = Ai[i]; rvj=Ax[i]; biasvj=bu[useri]; zvCoeff = (rvj - (mu + biasvj + biasi)) / (sqrt((double) numRatingUsers)); /* |R(i)|^-1/2 * (r_vj - b_vj) */ for (k=0;k<ls;k++) /* compute pu for each feature k*/ { zjk = z[ls*useri+k]; /* z[ls*useri+k] = z[ls,itemj] */ zv[k] += (zvCoeff * zjk); } } for (k=0; k<ls; k++) /* p_u' * z_v */ { r_hat_ui += ( p[ls*u+k] * zv[k] ); /* p_u(k) * zv(k) */ } } for (k=0; k<ls; k++) /* q_i' * pu */ { r_hat_ui += ( q[ls*itemj+k] * pu[k] ); /* q_i(k) * pu(k) */ } r_hat_ui += (mu + bu[u] + bi[itemj]); /* r_hat_ui = mu + bu + bi + q_i'*pu */ e_ui = Bx[j] - r_hat_ui; /* e_ui = r_ui - r_hat_ui */ if (log>1) fprintf(verbose,"(%d,%d)=%f\n",u,itemj,e_ui); if (mxIsNaN(e_ui) || mxIsInf(e_ui) || absolute(e_ui)>100000) { fprintf(stdout, " -!- [%d] -!- user=%d, item=%d, r=%f, r_hat=%f, e_ui=%f gradient error too large \n",anomaliesCounter,u,itemj,Bx[j],r_hat_ui,e_ui); fprintf(stdout, " biasu=%f, biasi=%f \n", bu[u], bi[itemj]); if (log>1) fclose(verbose); return; } if (absolute(e_ui)>7) { fprintf(stdout, " -!- [%d] -!- user=%d, item=%d, r=%f, r_hat=%f, e_ui=%f gradient error too large \n",anomaliesCounter,u,itemj,Bx[j],r_hat_ui,e_ui); fprintf(stdout, " biasu=%f, biasi=%f \n", bu[u], bi[itemj]); if (log>1) fclose(verbose); anomaliesCounter++; if (anomaliesCounter>maxAnomalies) return; } cumerror += (e_ui*e_ui); numTests++; for (k=0; k<ls; k++) /* sum <- sum + e_ui * q_i */ { sum[k] += (e_ui*q[ls*itemj+k]); /* sum(k) = e_ui * q_i(k) */ } if (useruser) /* sumUU <- sumUU + e_ui * p_u */ { for (k=0; k<ls; k++) { sumUU[k] += (e_ui*p[ls*u+k]); /* sumUU(k) = e_ui * p_u(k) */ } } /* perform gradient step on qi, bu, bi AND on "pu" if user-user model is enabled */ bu[u] += (lrateB * (e_ui - lambdaB*bu[u])); /* bu <- bu + gamma*(e_ui-lambdaB*bu) */ bi[itemj] += (lrateB * (e_ui - lambdaB*bi[itemj])); /* bi <- bi + gamma*(e_ui-lambdaB*bi) */ for (k=0; k<ls; k++) { q[ls*itemj+k] += (lrate * (e_ui*pu[k] - lambda* q[ls*itemj+k])); /* q_i <- q_i + gamma*(e_ui*pu-lambda*q_i) */ if (useruser) { p[ls*u+k] += (lrate * (e_ui*zv[k] - lambda* p[ls*u+k])); /* p_u <- p_u + gamma*(e_ui*zv-lambda*p_u) */ } } } /* FOR ALL i IN R(u) DO */ for (j=Bp[u]; j<Bp[u+1]; j++) /* perform gradient step on xi*/ { itemj = Bi[j]; double ruj = Bx[j]; double biasi = bi[itemj]; puCoeff = (1/sqrt(numRatedItems)) * (ruj - (mu + bu[u] + biasi)); /* |R(u)|^-1/2 * (r_ui - b_ui) */ for (k=0; k<ls; k++) { x[ls*itemj+k] += (lrate * ( puCoeff*sum[k] - lambda*x[ls*itemj+k] )); /* update of every feature of xi */ } if (useruser) { int useri; numRatingUsers = Ap [itemj+1] - Ap [itemj]; /* |R(i)| */ /* FOR ALL useri IN R(i) DO */ for (i=Ap[itemj]; i<Ap[itemj+1]; i++) /* perform gradient step on zv*/ { double rvj = Ax[i]; double biasvj; useri = Ai[i]; /* we are looping on all useri who rated itemj*/ biasvj = bu[useri]; /* bias user v*/ zvCoeff = (1/sqrt(numRatingUsers)) * (rvj - (mu + biasvj + biasi)); /* |R(i)|^-1/2 * (r_vj - b_vj) */ for (k=0; k<ls; k++) { z[ls*useri+k] += (lrate * ( zvCoeff*sumUU[k] - lambda*z[ls*useri+k] ) ); /* update of every feature of zv */ } } } } /* FOR ALL i IN N(u) DO */ for (j=Bp[u]; j<Bp[u+1]; j++) /* perform gradient step on yi*/ { itemj = Bi[j]; double ruj = Bx[j]; puCoeff = (1/sqrt(numRatedItems)); /* |N(u)|^-1/2 */ for (k=0; k<ls; k++) { y[ls*itemj+k] += (lrate * ( puCoeff*sum[k] - lambda*y[ls*itemj+k] ) ); /* update of every feature of yi */ } } if (log && ( ((u-1) % 10000 == 0)) ) { (void) time(&t2); fprintf(stdout, "[%d] time for last group (up to user %d) is %d secs - remaining Time =%d secs\n", (int) t2-t0,u, (int) t2-t1, (int) ( ( (t2-t0)/((double) u))*((double)((usersNum-u)*(count+1))))); if ((((double) (t2-t1))/10000.0)>1.0) fprintf (stdout, "warning... high computing time"); if (file_exists("~/stopnow")) return; (void) time(&t1); } } pseudoRMSE = cumerror / ((double) numTests); if (log) { fprintf(stdout, " cumulative error iteration %d = %g (%d tests) \n", count, pseudoRMSE,numTests); if (file_exists("~/stopiter")) return; } if (mxIsNaN(pseudoRMSE)) { fprintf(stdout, " -!- STOPPED -!- "); return; } } if (log>1) fclose(verbose); }