Skip to content
csr.h 5.15 KiB
Newer Older
#ifndef CSR_H
#define CSR_H

typedef int csi;
typedef double csv;
csv zero = 0.0;
#define CS_MAX(a,b) (((a) > (b)) ? (a) : (b))

typedef struct csr_t {
    csi  m; 
    csi  n; 
    csi  nzmax;
    csi  nr; 
    csi* r; 
    csi* p; 
    csi* j; 
    csv* x; 
} csr;
/* method declarations {{{*/
csr *csr_spfree(csr *A);
/*}}}*/

/*csr util{{{*/

/* free workspace and return a sparse matrix result */
csr *csr_done(csr *C, void *w, void *x, csi ok) {
    return(ok ? C : csr_spfree(C)); /* return result if OK, else free it */
}

/* wrapper for free */
void *cs_free(void *p) {
    if (p)
        free(p); /* free p if it is not already NULL */
    return(NULL); /* return NULL to simplify the use of cs_free */
}

/* wrapper for realloc */
void *csr_realloc(void *p, csi n, size_t size, csi *ok) {
    void *pnew = NULL;
    pnew = realloc(p, CS_MAX(n, 1) * size); /* realloc the block */
    *ok = (pnew != NULL); /* realloc fails if pnew is NULL */
    if (pnew == NULL) {
            printf("%d:reallocation failed, pnew is NULL\n", __LINE__);
    }
    return((*ok) ? pnew : p); /* return original p if failure */
}

/* wrapper for realloc */
void *cs_realloc(void *p, csi n, size_t size, csi *ok) {
    void *pnew = NULL;
    pnew = realloc(p, CS_MAX(n, 1) * size); /* realloc the block */
    *ok = (pnew != NULL); /* realloc fails if pnew is NULL */
    if (pnew == NULL) {
            printf("reallocation failed\n");
    }
    return((*ok) ? pnew : p); /* return original p if failure */
}

/* change the max # of entries sparse matrix */
csi csr_sprealloc(csr *A, csi nzmax) {
    csi ok, oki = 0, okj = 1, okx = 1;
    if (!A)
            return(0);
    if (nzmax <= 0)
            nzmax = A->p[A->m];
    A->j = (int*)csr_realloc(A->j, nzmax, sizeof(csi), &oki);
    if (A->x)
            A->x = (csv*)csr_realloc(A->x, nzmax, sizeof(csv), &okx);
    ok = (oki && okj && okx);
    if (ok)
            A->nzmax = nzmax;
    return(ok);
}

/* free a sparse matrix */
csr *csr_spfree(csr *A) {
    if (!A)
            return(NULL); /* do nothing if A already NULL */
    cs_free(A->p);
    A->p = NULL;
    cs_free(A->j);
    A->j = NULL;
    cs_free(A->x);
    A->x = NULL;
    cs_free(A->r);
    A->r = NULL;
    cs_free(A); /* free the cs struct and return NULL */
    return NULL;
}

/* allocate a sparse matrix (triplet form or compressed-ROW form) */
csr *csr_spalloc(csi m, csi n, csi nzmax, int values, int triplet, csv f) {
    csr* A = (csr*)calloc(1, sizeof(csr)); /* allocate the cs struct */
    if (!A) {
            perror("sparse allocation failed");
            return(NULL); /* out of memory */
    }
    A->m = m; /* define dimensions and nzmax */
    A->n = n;
    A->nzmax = nzmax = CS_MAX(nzmax, 0);
    A->nr = 0;  // number of nonzero rows
    A->p = (csi*)calloc(m + 2, sizeof(csi));
    A->j = (csi*)calloc(CS_MAX(nzmax,1), sizeof(csi));
    A->x = (csv*)calloc(CS_MAX(nzmax,1), sizeof(csv));
    return((!A->p || !A->j || !A->x) ? csr_spfree(A) : A);
}/*}}}*/

/** Multiply two sparse matrices which are stored in CSR format. MKL is used */
csr *csr_multiply(csi Am, csi An, csi Anzmax, const csi* Ap, const csi* Aj, const csv* Ax, csi Bm, csi Bn, csi Bnzmax, const csi* Bp, const csi* Bj, const csv* Bx, long* nummult, csi* xb, csv* x) { /*{{{*/
    csv tf = 0;
    csi p, jp, j, kp, k, i, nz = 0, anz, *Cp, *Cj, m, n,
        bnz, values = 1;
    csv *Cx;
    csr *C;
    if (An != Bm)
        return(NULL);
    if (Anzmax == 0 || Bnzmax == 0) {
        C = csr_spalloc(Am, Bn, 0, values, 0, tf);
        return C;
    }
    m = Am;
    anz = Ap[Am];
    n = Bn;
    bnz = Bp[Bm];
    for(i = 0; i < n; i++) xb[i] = 0;
    for(i = 0; i < n; i++)
        xb[i] = 0;
    values = (Ax != NULL) && (Bx != NULL);
    csi tnz = (anz + bnz) * 2;
    C = csr_spalloc(m, n, tnz, values, 0, tf); /* allocate result */
    if (!C || !xb || (values && !x))
        return (csr_done(C, xb, x, 0));
    Cp = C->p;
    for (i = 0; i < m; i++) {
        if ( ( (nz + n) > C->nzmax ) ) {
            if(!csr_sprealloc(C, (2 * (C->nzmax) + n) ) ) {
                return (csr_done(C, xb, x, 0)); // out of memory
            } else {
            }
        }
        Cj = C->j;
        Cx = C->x; /* C->j and C->x may be reallocated */
        Cp[i] = nz; /* row i of C starts here */
        for (jp = Ap[i]; jp < Ap[i + 1]; jp++) {
            j = Aj[jp];
            for (kp = Bp[j]; kp < Bp[j + 1]; kp++) {
                k = Bj[kp]; /* B(i,j) is nonzero */
                if (xb[k] != i + 1) {
                    xb[k] = i + 1; /* i is new entry in column j */
                    Cj[nz++] = k; /* add i to pattern of C(:,j) */
                    if (x) {
                        x[k] = Ax[jp] * Bx[kp]; /* x(i) = beta*A(i,j) */
                        (*nummult)++;
                    }
                } else if (x) {
                    x[k] += (Ax[jp] * Bx[kp]); /* i exists in C(:,j) already */
                    (*nummult)++;
                }
            }
        }
        if (values)
            for (p = Cp[i]; p < nz; p++)
                Cx[p] = x[Cj[p]];
    }
    Cp[m] = nz; /* finalize the last row of C */
    csr_sprealloc(C, 0); /* remove extra space from C */
    xb = NULL;
    x = NULL;
    return C;
}/*}}}*/

#endif