/* ========================================================================== */
/* === Cholesky/cholmod_spsolve ============================================= */
/* ========================================================================== */
/* -----------------------------------------------------------------------------
* CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis
* The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
* Lesser General Public License. See lesser.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
* -------------------------------------------------------------------------- */
/* Given an LL' or LDL' factorization of A, solve one of the following systems:
*
* Ax=b 0: CHOLMOD_A also applies the permutation L->Perm
* LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm
* LDx=b 2: CHOLMOD_LD
* DL'x=b 3: CHOLMOD_DLt
* Lx=b 4: CHOLMOD_L
* L'x=b 5: CHOLMOD_Lt
* Dx=b 6: CHOLMOD_D
* x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm)
* x=P'b 8: CHOLMOD_Pt apply an inverse permutation
*
* where b and x are sparse. If L and b are real, then x is real. Otherwise,
* x is complex or zomplex, depending on the Common->prefer_zomplex parameter.
* All xtypes of x and b are supported (real, complex, and zomplex).
*/
#ifndef NCHOLESKY
#include "cholmod_internal.h"
#include "cholmod_cholesky.h"
/* ========================================================================== */
/* === EXPAND_AS_NEEDED ===================================================== */
/* ========================================================================== */
/* Double the size of the sparse matrix X, if we have run out of space. */
#define EXPAND_AS_NEEDED \
if (xnz >= nzmax) \
{ \
nzmax *= 2 ; \
CHOLMOD(reallocate_sparse) (nzmax, X, Common) ; \
if (Common->status < CHOLMOD_OK) \
{ \
CHOLMOD(free_sparse) (&X, Common) ; \
CHOLMOD(free_dense) (&X4, Common) ; \
CHOLMOD(free_dense) (&B4, Common) ; \
return (NULL) ; \
} \
Xi = X->i ; \
Xx = X->x ; \
Xz = X->z ; \
}
/* ========================================================================== */
/* === cholmod_spolve ======================================================= */
/* ========================================================================== */
cholmod_sparse *CHOLMOD(spsolve) /* returns the sparse solution X */
(
/* ---- input ---- */
int sys, /* system to solve */
cholmod_factor *L, /* factorization to use */
cholmod_sparse *B, /* right-hand-side */
/* --------------- */
cholmod_common *Common
)
{
double x, z ;
cholmod_dense *X4, *B4 ;
cholmod_sparse *X ;
double *Bx, *Bz, *Xx, *Xz, *B4x, *B4z, *X4x, *X4z ;
Int *Bi, *Bp, *Xp, *Xi, *Bnz ;
Int n, nrhs, q, p, i, j, j1, j2, packed, block, pend, jn, xtype ;
size_t xnz, nzmax ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
RETURN_IF_NULL_COMMON (NULL) ;
RETURN_IF_NULL (L, NULL) ;
RETURN_IF_NULL (B, NULL) ;
RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
if (L->n != B->nrow)
{
ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ;
return (NULL) ;
}
if (B->stype)
{
ERROR (CHOLMOD_INVALID, "B cannot be stored in symmetric mode") ;
return (NULL) ;
}
Common->status = CHOLMOD_OK ;
/* ---------------------------------------------------------------------- */
/* allocate workspace B4 and initial result X */
/* ---------------------------------------------------------------------- */
n = L->n ;
nrhs = B->ncol ;
/* X is real if both L and B are real, complex/zomplex otherwise */
xtype = (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) ?
CHOLMOD_REAL :
(Common->prefer_zomplex ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX) ;
/* solve up to 4 columns at a time */
block = MIN (nrhs, 4) ;
/* initial size of X is at most 4*n */
nzmax = n*block ;
X = CHOLMOD(spzeros) (n, nrhs, nzmax, xtype, Common) ;
B4 = CHOLMOD(zeros) (n, block, B->xtype, Common) ;
if (Common->status < CHOLMOD_OK)
{
CHOLMOD(free_sparse) (&X, Common) ;
CHOLMOD(free_dense) (&B4, Common) ;
return (NULL) ;
}
Bp = B->p ;
Bi = B->i ;
Bx = B->x ;
Bz = B->z ;
Bnz = B->nz ;
packed = B->packed ;
Xp = X->p ;
Xi = X->i ;
Xx = X->x ;
Xz = X->z ;
xnz = 0 ;
B4x = B4->x ;
B4z = B4->z ;
/* ---------------------------------------------------------------------- */
/* solve in chunks of 4 columns at a time */
/* ---------------------------------------------------------------------- */
for (j1 = 0 ; j1 < nrhs ; j1 += block)
{
/* ------------------------------------------------------------------ */
/* adjust the number of columns of B4 */
/* ------------------------------------------------------------------ */
j2 = MIN (nrhs, j1 + block) ;
B4->ncol = j2 - j1 ;
/* ------------------------------------------------------------------ */
/* scatter B(j1:j2-1) into B4 */
/* ------------------------------------------------------------------ */
for (j = j1 ; j < j2 ; j++)
{
p = Bp [j] ;
pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ;
jn = (j-j1)*n ;
switch (B->xtype)
{
case CHOLMOD_REAL:
for ( ; p < pend ; p++)
{
B4x [Bi [p] + jn] = Bx [p] ;
}
break ;
case CHOLMOD_COMPLEX:
for ( ; p < pend ; p++)
{
q = Bi [p] + jn ;
B4x [2*q ] = Bx [2*p ] ;
B4x [2*q+1] = Bx [2*p+1] ;
}
break ;
case CHOLMOD_ZOMPLEX:
for ( ; p < pend ; p++)
{
q = Bi [p] + jn ;
B4x [q] = Bx [p] ;
B4z [q] = Bz [p] ;
}
break ;
}
}
/* ------------------------------------------------------------------ */
/* solve the system (X4 = A\B4 or other system) */
/* ------------------------------------------------------------------ */
X4 = CHOLMOD(solve) (sys, L, B4, Common) ;
if (Common->status < CHOLMOD_OK)
{
CHOLMOD(free_sparse) (&X, Common) ;
CHOLMOD(free_dense) (&B4, Common) ;
CHOLMOD(free_dense) (&X4, Common) ;
return (NULL) ;
}
ASSERT (X4->xtype == xtype) ;
X4x = X4->x ;
X4z = X4->z ;
/* ------------------------------------------------------------------ */
/* append the solution onto X */
/* ------------------------------------------------------------------ */
for (j = j1 ; j < j2 ; j++)
{
Xp [j] = xnz ;
jn = (j-j1)*n ;
if ( xnz + n <= nzmax)
{
/* ---------------------------------------------------------- */
/* X is guaranteed to be large enough */
/* ---------------------------------------------------------- */
switch (xtype)
{
case CHOLMOD_REAL:
for (i = 0 ; i < n ; i++)
{
x = X4x [i + jn] ;
if (IS_NONZERO (x))
{
Xi [xnz] = i ;
Xx [xnz] = x ;
xnz++ ;
}
}
break ;
case CHOLMOD_COMPLEX:
for (i = 0 ; i < n ; i++)
{
x = X4x [2*(i + jn) ] ;
z = X4x [2*(i + jn)+1] ;
if (IS_NONZERO (x) || IS_NONZERO (z))
{
Xi [xnz] = i ;
Xx [2*xnz ] = x ;
Xx [2*xnz+1] = z ;
xnz++ ;
}
}
break ;
case CHOLMOD_ZOMPLEX:
for (i = 0 ; i < n ; i++)
{
x = X4x [i + jn] ;
z = X4z [i + jn] ;
if (IS_NONZERO (x) || IS_NONZERO (z))
{
Xi [xnz] = i ;
Xx [xnz] = x ;
Xz [xnz] = z ;
xnz++ ;
}
}
break ;
}
}
else
{
/* ---------------------------------------------------------- */
/* X may need to increase in size */
/* ---------------------------------------------------------- */
switch (xtype)
{
case CHOLMOD_REAL:
for (i = 0 ; i < n ; i++)
{
x = X4x [i + jn] ;
if (IS_NONZERO (x))
{
EXPAND_AS_NEEDED ;
Xi [xnz] = i ;
Xx [xnz] = x ;
xnz++ ;
}
}
break ;
case CHOLMOD_COMPLEX:
for (i = 0 ; i < n ; i++)
{
x = X4x [2*(i + jn) ] ;
z = X4x [2*(i + jn)+1] ;
if (IS_NONZERO (x) || IS_NONZERO (z))
{
EXPAND_AS_NEEDED ;
Xi [xnz] = i ;
Xx [2*xnz ] = x ;
Xx [2*xnz+1] = z ;
xnz++ ;
}
}
break ;
case CHOLMOD_ZOMPLEX:
for (i = 0 ; i < n ; i++)
{
x = X4x [i + jn] ;
z = X4z [i + jn] ;
if (IS_NONZERO (x) || IS_NONZERO (z))
{
EXPAND_AS_NEEDED ;
Xi [xnz] = i ;
Xx [xnz] = x ;
Xz [xnz] = z ;
xnz++ ;
}
}
break ;
}
}
}
CHOLMOD(free_dense) (&X4, Common) ;
/* ------------------------------------------------------------------ */
/* clear B4 for next iteration */
/* ------------------------------------------------------------------ */
if (j2 < nrhs)
{
for (j = j1 ; j < j2 ; j++)
{
p = Bp [j] ;
pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ;
jn = (j-j1)*n ;
switch (B->xtype)
{
case CHOLMOD_REAL:
for ( ; p < pend ; p++)
{
B4x [Bi [p] + jn] = 0 ;
}
break ;
case CHOLMOD_COMPLEX:
for ( ; p < pend ; p++)
{
q = Bi [p] + jn ;
B4x [2*q ] = 0 ;
B4x [2*q+1] = 0 ;
}
break ;
case CHOLMOD_ZOMPLEX:
for ( ; p < pend ; p++)
{
q = Bi [p] + jn ;
B4x [q] = 0 ;
B4z [q] = 0 ;
}
break ;
}
}
}
}
Xp [nrhs] = xnz ;
/* ---------------------------------------------------------------------- */
/* reduce X in size, free workspace, and return result */
/* ---------------------------------------------------------------------- */
ASSERT (xnz <= X->nzmax) ;
CHOLMOD(reallocate_sparse) (xnz, X, Common) ;
ASSERT (Common->status == CHOLMOD_OK) ;
CHOLMOD(free_dense) (&B4, Common) ;
return (X) ;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1