The R Project SVN R-packages

Rev

Rev 3695 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/* ========================================================================== */
/* === Supernodal/t_cholmod_super_solve ===================================== */
/* ========================================================================== */

/* -----------------------------------------------------------------------------
 * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
 * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
 * General Public License.  See gpl.txt for a text of the license.
 * CHOLMOD is also available under other licenses; contact authors for details.
 * http://www.cise.ufl.edu/research/sparse
 * -------------------------------------------------------------------------- */

/* Template routine for cholmod_super_solve.  Supports real or complex L. */

#include "cholmod_template.h"

static int TEMPLATE (cholmod_super_lsolve)
(
    /* ---- input ---- */
    cholmod_factor *L,  /* factor to use for the forward solve */
    /* ---- output ---- */
    cholmod_dense *X,   /* b on input, solution to Lx=b on output */
    /* ---- workspace ---- */
    cholmod_dense *E,   /* workspace of size nrhs*(L->maxesize) */
    /* --------------- */
    cholmod_common *Common
)
{
    double *Lx, *Xx, *Ex ;
    double minus_one [2], one [2] ;
    Int *Lpi, *Lpx, *Ls, *Super ;
    Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s,
    nsrow2, n, ps2, j, i, d, nrhs ;

    /* If integer overflow occurs in the BLAS, Common->status is set to
     * CHOLMOD_TOO_LARGE in the caller, and the contents of X are undefined. */
    int blas_ok = TRUE ;

    /* ---------------------------------------------------------------------- */
    /* get inputs */
    /* ---------------------------------------------------------------------- */

    nrhs = X->ncol ;
    Ex = E->x ;
    Xx = X->x ;
    n = L->n ;
    d = X->d ;

    nsuper = L->nsuper ;
    Lpi = L->pi ;
    Lpx = L->px ;
    Ls = L->s ;
    Super = L->super ;
    Lx = L->x ;
    minus_one [0] = -1.0 ;
    minus_one [1] = 0 ;
    one [0] = 1.0 ;
    one [1] = 0 ;

    /* ---------------------------------------------------------------------- */
    /* solve Lx=b */
    /* ---------------------------------------------------------------------- */

    if (nrhs == 1)
    {

    for (s = 0 ; s < nsuper ; s++)
    {
        k1 = Super [s] ;
        k2 = Super [s+1] ;
        psi = Lpi [s] ;
        psend = Lpi [s+1] ;
        psx = Lpx [s] ;
        nsrow = psend - psi ;
        nscol = k2 - k1 ;
        nsrow2 = nsrow - nscol ;
        ps2 = psi + nscol ;
        ASSERT ((size_t) nsrow2 <= L->maxesize) ;

        /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal.
         * L2 is nsrow2-by-nscol.  L1 and L2 have leading dimension of
         * nsrow.  x1 is nscol-by-nsrow, with leading dimension n.
         * E is nsrow2-by-1, with leading dimension nsrow2.
         */

        /* gather X into E */
        for (ii = 0 ; ii < nsrow2 ; ii++)
        {
        /* Ex [ii] = Xx [Ls [ps2 + ii]] ; */
        ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ;
        }

#ifdef REAL

        /* solve L1*x1 (that is, x1 = L1\x1) */
        BLAS_dtrsv ("L", "N", "N",
        nscol,              /* N:       L1 is nscol-by-nscol */
        Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA:  L1 */
        Xx + ENTRY_SIZE*k1, 1) ;    /* X, INCX: x1 */

        /* E = E - L2*x1 */
        BLAS_dgemv ("N",
        nsrow2, nscol,          /* M, N:    L2 is nsrow2-by-nscol */
        minus_one,          /* ALPHA:   -1 */
        Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
        nsrow,
        Xx + ENTRY_SIZE*k1, 1,      /* X, INCX: x1 */
        one,                /* BETA:    1 */
        Ex, 1) ;            /* Y, INCY: E */

#else

        /* solve L1*x1 (that is, x1 = L1\x1) */
        BLAS_ztrsv ("L", "N", "N",
        nscol,              /* N:       L1 is nscol-by-nscol */
        Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA:  L1 */
        Xx + ENTRY_SIZE*k1, 1) ;    /* X, INCX: x1 */

        /* E = E - L2*x1 */
        BLAS_zgemv ("N",
        nsrow2, nscol,          /* M, N:    L2 is nsrow2-by-nscol */
        minus_one,          /* ALPHA:   -1 */
        Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
        nsrow,
        Xx + ENTRY_SIZE*k1, 1,      /* X, INCX: x1 */
        one,                /* BETA:    1 */
        Ex, 1) ;            /* Y, INCY: E */

#endif

        /* scatter E back into X */
        for (ii = 0 ; ii < nsrow2 ; ii++)
        {
        /* Xx [Ls [ps2 + ii]] = Ex [ii] ; */
        ASSIGN (Xx,-,Ls [ps2 + ii], Ex,-,ii) ;
        }
    }
    }
    else
    {

    for (s = 0 ; s < nsuper ; s++)
    {
        k1 = Super [s] ;
        k2 = Super [s+1] ;
        psi = Lpi [s] ;
        psend = Lpi [s+1] ;
        psx = Lpx [s] ;
        nsrow = psend - psi ;
        nscol = k2 - k1 ;
        nsrow2 = nsrow - nscol ;
        ps2 = psi + nscol ;
        ASSERT ((size_t) nsrow2 <= L->maxesize) ;

        /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */

        /* gather X into E */
        for (ii = 0 ; ii < nsrow2 ; ii++)
        {
        i = Ls [ps2 + ii] ;
        for (j = 0 ; j < nrhs ; j++)
        {
            /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */
            ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ;
        }
        }

#ifdef REAL

        /* solve L1*x1 */
        BLAS_dtrsm ("L", "L", "N", "N",
        nscol, nrhs,            /* M, N: x1 is nscol-by-nrhs */
        one,                /* ALPHA:  1 */
        Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */
        Xx + ENTRY_SIZE*k1, d) ;    /* B, LDB: x1 */

        /* E = E - L2*x1 */
        if (nsrow2 > 0)
        {
        BLAS_dgemm ("N", "N",
            nsrow2, nrhs, nscol,        /* M, N, K */
            minus_one,              /* ALPHA:  -1 */
            Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
            nsrow,
            Xx + ENTRY_SIZE*k1, d,      /* B, LDB: X1 */
            one,                /* BETA:   1 */
            Ex, nsrow2) ;           /* C, LDC: E */
        }

#else

        /* solve L1*x1 */
        BLAS_ztrsm ("L", "L", "N", "N",
        nscol, nrhs,            /* M, N: x1 is nscol-by-nrhs */
        one,                /* ALPHA:  1 */
        Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */
        Xx + ENTRY_SIZE*k1, d) ;    /* B, LDB: x1 */

        /* E = E - L2*x1 */
        if (nsrow2 > 0)
        {
        BLAS_zgemm ("N", "N",
            nsrow2, nrhs, nscol,        /* M, N, K */
            minus_one,              /* ALPHA:  -1 */
            Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
            nsrow,
            Xx + ENTRY_SIZE*k1, d,      /* B, LDB: X1 */
            one,                /* BETA:   1 */
            Ex, nsrow2) ;           /* C, LDC: E */
        }

#endif

        /* scatter E back into X */
        for (ii = 0 ; ii < nsrow2 ; ii++)
        {
        i = Ls [ps2 + ii] ;
        for (j = 0 ; j < nrhs ; j++)
        {
            /* Xx [i + j*d] = Ex [ii + j*nsrow2] ; */
            ASSIGN (Xx,-,i+j*d, Ex,-,ii+j*nsrow2) ;
        }
        }
    }
    }

    Common->status = CHOLMOD_OK ;
    return (blas_ok) ;
}


static int TEMPLATE (cholmod_super_ltsolve)
(
    /* ---- input ---- */
    cholmod_factor *L,  /* factor to use for the forward solve */
    /* ---- output ---- */
    cholmod_dense *X,   /* b on input, solution to Lx=b on output */
    /* ---- workspace ---- */
    cholmod_dense *E,   /* workspace of size nrhs*(L->maxesize) */
    /* --------------- */
    cholmod_common *Common
)
{
    double *Lx, *Xx, *Ex ;
    double minus_one [2], one [2] ;
    Int *Lpi, *Lpx, *Ls, *Super ;
    Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s,
    nsrow2, n, ps2, j, i, d, nrhs ;
    int blas_ok = TRUE ;

    /* ---------------------------------------------------------------------- */
    /* get inputs */
    /* ---------------------------------------------------------------------- */

    nrhs = X->ncol ;
    Ex = E->x ;
    Xx = X->x ;
    n = L->n ;
    d = X->d ;

    nsuper = L->nsuper ;
    Lpi = L->pi ;
    Lpx = L->px ;
    Ls = L->s ;
    Super = L->super ;
    Lx = L->x ;
    minus_one [0] = -1.0 ;
    minus_one [1] = 0 ;
    one [0] = 1.0 ;
    one [1] = 0 ;

    /* ---------------------------------------------------------------------- */
    /* solve L'x=b */
    /* ---------------------------------------------------------------------- */

    if (nrhs == 1)
    {

    for (s = nsuper-1 ; s >= 0 ; s--)
    {
        k1 = Super [s] ;
        k2 = Super [s+1] ;
        psi = Lpi [s] ;
        psend = Lpi [s+1] ;
        psx = Lpx [s] ;
        nsrow = psend - psi ;
        nscol = k2 - k1 ;
        nsrow2 = nsrow - nscol ;
        ps2 = psi + nscol ;
        ASSERT ((size_t) nsrow2 <= L->maxesize) ;

        /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal.
         * L2 is nsrow2-by-nscol.  L1 and L2 have leading dimension of
         * nsrow.  x1 is nscol-by-nsrow, with leading dimension n.
         * E is nsrow2-by-1, with leading dimension nsrow2.
         */

        /* gather X into E */
        for (ii = 0 ; ii < nsrow2 ; ii++)
        {
        /* Ex [ii] = Xx [Ls [ps2 + ii]] ; */
        ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ;
        }

#ifdef REAL

        /* x1 = x1 - L2'*E */
        BLAS_dgemv ("C",
        nsrow2, nscol,          /* M, N: L2 is nsrow2-by-nscol */
        minus_one,          /* ALPHA:   -1 */
        Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
        nsrow,
        Ex, 1,              /* X, INCX: Ex */
        one,                /* BETA:    1 */
        Xx + ENTRY_SIZE*k1, 1) ;    /* Y, INCY: x1 */

        /* solve L1'*x1 */
        BLAS_dtrsv ("L", "C", "N",
        nscol,              /* N:   L1 is nscol-by-nscol */
        Lx + ENTRY_SIZE*psx, nsrow,     /* A, LDA:  L1 */
        Xx + ENTRY_SIZE*k1, 1) ;        /* X, INCX: x1 */

#else

        /* x1 = x1 - L2'*E */
        BLAS_zgemv ("C",
        nsrow2, nscol,          /* M, N: L2 is nsrow2-by-nscol */
        minus_one,          /* ALPHA:   -1 */
        Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
        nsrow,
        Ex, 1,              /* X, INCX: Ex */
        one,                /* BETA:    1 */
        Xx + ENTRY_SIZE*k1, 1) ;    /* Y, INCY: x1 */

        /* solve L1'*x1 */
        BLAS_ztrsv ("L", "C", "N",
        nscol,              /* N:   L1 is nscol-by-nscol */
        Lx + ENTRY_SIZE*psx, nsrow,     /* A, LDA:  L1 */
        Xx + ENTRY_SIZE*k1, 1) ;        /* X, INCX: x1 */

#endif

    }
    }
    else
    {

    for (s = nsuper-1 ; s >= 0 ; s--)
    {
        k1 = Super [s] ;
        k2 = Super [s+1] ;
        psi = Lpi [s] ;
        psend = Lpi [s+1] ;
        psx = Lpx [s] ;
        nsrow = psend - psi ;
        nscol = k2 - k1 ;
        nsrow2 = nsrow - nscol ;
        ps2 = psi + nscol ;
        ASSERT ((size_t) nsrow2 <= L->maxesize) ;

        /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */

        /* gather X into E */
        for (ii = 0 ; ii < nsrow2 ; ii++)
        {
        i = Ls [ps2 + ii] ;
        for (j = 0 ; j < nrhs ; j++)
        {
            /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */
            ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ;
        }
        }

#ifdef REAL

        /* x1 = x1 - L2'*E */
        if (nsrow2 > 0)
        {
        BLAS_dgemm ("C", "N",
            nscol, nrhs, nsrow2,    /* M, N, K */
            minus_one,          /* ALPHA:  -1 */
            Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
            nsrow,
            Ex, nsrow2,         /* B, LDB: E */
            one,            /* BETA:   1 */
            Xx + ENTRY_SIZE*k1, d) ;    /* C, LDC: x1 */
        }

        /* solve L1'*x1 */
        BLAS_dtrsm ("L", "L", "C", "N",
        nscol,  nrhs,           /* M, N: x1 is nscol-by-nrhs */
        one,                /* ALPHA:  1 */
        Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */
        Xx + ENTRY_SIZE*k1, d) ;    /* B, LDB: x1 */

#else

        /* x1 = x1 - L2'*E */
        if (nsrow2 > 0)
        {
        BLAS_zgemm ("C", "N",
            nscol, nrhs, nsrow2,    /* M, N, K */
            minus_one,          /* ALPHA:  -1 */
            Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
            nsrow,
            Ex, nsrow2,         /* B, LDB: E */
            one,            /* BETA:   1 */
            Xx + ENTRY_SIZE*k1, d) ;    /* C, LDC: x1 */
        }

        /* solve L1'*x1 */
        BLAS_ztrsm ("L", "L", "C", "N",
        nscol,  nrhs,           /* M, N: x1 is nscol-by-nrhs */
        one,                /* ALPHA:  1 */
        Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */
        Xx + ENTRY_SIZE*k1, d) ;    /* B, LDB: x1 */

#endif

    }
    }

    Common->status = CHOLMOD_OK ;
    return (blas_ok) ;
}

#undef PATTERN
#undef REAL
#undef COMPLEX
#undef ZOMPLEX