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 */
    }
}
Beispiel #2
0
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) ;
}
Beispiel #3
0
/* 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 */
    }
}
Beispiel #4
0
/* 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)") ;
        }
    }
}
Beispiel #5
0
/* 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) ;
    }
}
Beispiel #6
0
/* 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 */
        }

}
Beispiel #9
0
/* 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);
    
}