ngspice/src/maths/KLU/klu_utils.c

352 lines
7.7 KiB
C

#include "ngspice/memory.h"
#include "klu_internal.h"
typedef struct sElement {
Int row ;
Int col ;
Entry val ;
} Element ;
static int
CompareRow (const void *a, const void *b)
{
Element *A = (Element *) a ;
Element *B = (Element *) b ;
return
(A->row > B->row) ? 1 :
(A->row < B->row) ? -1 :
0 ;
}
static int
CompareColumn (const void *a, const void *b)
{
Element *A = (Element *) a ;
Element *B = (Element *) b ;
return
(A->col > B->col) ? 1 :
(A->col < B->col) ? -1 :
0 ;
}
static void
Compress (Int *Ai, Int *Bp, int num_rows, int n_COO)
{
int i, j ;
for (i = 0 ; i <= Ai [0] ; i++)
Bp [i] = 0 ;
j = Ai [0] + 1 ;
for (i = 1 ; i < n_COO ; i++)
{
if (Ai [i] == Ai [i - 1] + 1)
{
Bp [j] = i ;
j++ ;
}
else if (Ai [i] > Ai [i - 1] + 1)
{
for ( ; j <= Ai [i] ; j++)
Bp [j] = i ;
}
}
for ( ; j <= num_rows ; j++)
Bp [j] = i ;
}
Int
KLU_convert_matrix_in_CSR /* return TRUE if successful, FALSE otherwise */
(
Int *Ap_CSC, /* CSC */
Int *Ai_CSC, /* CSC */
double *Ax_CSC, /* CSC */
Int *Ap_CSR, /* CSR */
Int *Ai_CSR, /* CSR */
double *Ax_CSR, /* CSR */
Int n,
Int nz,
KLU_common *Common
)
{
Element *MatrixCOO ;
Entry *Az_CSC, *Az_CSR ;
Int *Ap_COO, i, j, k ;
/* ---------------------------------------------------------------------- */
/* check inputs */
/* ---------------------------------------------------------------------- */
if (Common == NULL)
{
return (FALSE) ;
}
if (Ap_CSC != NULL)
{
if (Ai_CSC == NULL || Ax_CSC == NULL)
{
/* CSC Matrix is empty, so the CSR one */
for (i = 0 ; i <= n ; i++)
{
Ap_CSR [i] = 0 ;
}
Common->status = KLU_OK ;
return (TRUE) ;
}
} else {
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->status = KLU_OK ;
MatrixCOO = TMALLOC(Element, nz);
Ap_COO = TMALLOC(Int, nz);
Az_CSC = (Entry *)Ax_CSC ;
Az_CSR = (Entry *)Ax_CSR ;
k = 0 ;
for (i = 0 ; i < n ; i++)
{
for (j = Ap_CSC [i] ; j < Ap_CSC [i + 1] ; j++)
{
MatrixCOO [k].row = Ai_CSC [j] ;
MatrixCOO [k].col = i ;
#ifdef COMPLEX
MatrixCOO [k].val.Real = Az_CSC [j].Real ;
MatrixCOO [k].val.Imag = Az_CSC [j].Imag ;
#else
MatrixCOO [k].val = Az_CSC [j] ;
#endif
k++ ;
}
}
/* Order the MatrixCOO along the rows */
qsort (MatrixCOO, (size_t)nz, sizeof(Element), CompareRow) ;
/* Order the MatrixCOO along the columns */
i = 0 ;
while (i < nz)
{
for (j = i + 1 ; j < nz ; j++)
{
if (MatrixCOO [j].row != MatrixCOO [i].row)
{
break ;
}
}
qsort (MatrixCOO + i, (size_t)(j - i), sizeof(Element), CompareColumn) ;
i = j ;
}
for (i = 0 ; i < nz ; i++)
{
Ap_COO [i] = MatrixCOO [i].row ;
Ai_CSR [i] = MatrixCOO [i].col ;
#ifdef COMPLEX
Az_CSR [i].Real = MatrixCOO [i].val.Real ;
Az_CSR [i].Imag = MatrixCOO [i].val.Imag ;
#else
Az_CSR [i] = MatrixCOO [i].val ;
#endif
}
Compress (Ap_COO, Ap_CSR, n, nz) ;
free (MatrixCOO) ;
free (Ap_COO) ;
return (TRUE) ;
}
/* Francesco - Extract only Udiag */
Int KLU_extract_Udiag /* returns TRUE if successful, FALSE otherwise */
(
/* inputs: */
KLU_numeric *Numeric,
KLU_symbolic *Symbolic,
/* outputs, all of which must be allocated on input */
/* U */
double *Ux, /* size nnz(U) */
#ifdef COMPLEX
double *Uz, /* size nnz(U) for the complex case, ignored if real */
#endif
Int *P,
Int *Q,
double *Rs,
KLU_common *Common
)
{
Entry *Ukk ;
Int block, k1, k2, kk, i, n, nk, nblocks, nz ;
if (Common == NULL)
{
return (FALSE) ;
}
if (Common->status == KLU_EMPTY_MATRIX)
{
return (FALSE) ;
}
if (Symbolic == NULL || Numeric == NULL)
{
Common->status = KLU_INVALID ;
return (FALSE) ;
}
Common->status = KLU_OK ;
n = Symbolic->n ;
nblocks = Symbolic->nblocks ;
/* ---------------------------------------------------------------------- */
/* extract scale factors */
/* ---------------------------------------------------------------------- */
if (Rs != NULL)
{
if (Numeric->Rs != NULL)
{
for (i = 0 ; i < n ; i++)
{
Rs [i] = Numeric->Rs [i] ;
}
}
else
{
/* no scaling */
for (i = 0 ; i < n ; i++)
{
Rs [i] = 1 ;
}
}
}
/* ---------------------------------------------------------------------- */
/* extract final row permutation */
/* ---------------------------------------------------------------------- */
if (P != NULL)
{
for (i = 0 ; i < n ; i++)
{
P [i] = Numeric->Pnum [i] ;
}
}
/* ---------------------------------------------------------------------- */
/* extract column permutation */
/* ---------------------------------------------------------------------- */
if (Q != NULL)
{
for (i = 0 ; i < n ; i++)
{
Q [i] = Symbolic->Q [i] ;
}
}
/* ---------------------------------------------------------------------- */
/* extract each block of U */
/* ---------------------------------------------------------------------- */
if (Ux != NULL
#ifdef COMPLEX
&& Uz != NULL
#endif
)
{
nz = 0 ;
for (block = 0 ; block < nblocks ; block++)
{
k1 = Symbolic->R [block] ;
k2 = Symbolic->R [block+1] ;
nk = k2 - k1 ;
Ukk = ((Entry *) Numeric->Udiag) + k1 ;
if (nk == 1)
{
/* singleton block */
Ux [nz] = REAL (Ukk [0]) ;
#ifdef COMPLEX
Uz [nz] = IMAG (Ukk [0]) ;
#endif
nz++ ;
}
else
{
/* non-singleton block */
for (kk = 0 ; kk < nk ; kk++)
{
/* add the diagonal entry */
Ux [nz] = REAL (Ukk [kk]) ;
#ifdef COMPLEX
Uz [nz] = IMAG (Ukk [kk]) ;
#endif
nz++ ;
}
}
}
ASSERT (nz == Numeric->unz) ;
}
return (TRUE) ;
}
Int KLU_print
(
Int *Ap,
Int *Ai,
double *Ax,
int n,
int *IntToExtRowMap,
int *IntToExtColMap
)
{
Entry *Az ;
int i, j ;
Az = (Entry *)Ax ;
for (i = 0 ; i < n ; i++)
{
for (j = Ap [i] ; j < Ap [i + 1] ; j++)
{
#ifdef COMPLEX
if (IntToExtRowMap && IntToExtColMap) {
fprintf (stderr, "Row: %d\tCol: %d\tValue: %-.9g j%-.9g\n", IntToExtRowMap [Ai [j] + 1], IntToExtColMap [i + 1], Az [j].Real, Az [j].Imag) ;
} else {
fprintf (stderr, "Row: %d\tCol: %d\tValue: %-.9g j%-.9g\n", Ai [j] + 1, i + 1, Az [j].Real, Az [j].Imag) ;
}
#else
if (IntToExtRowMap && IntToExtColMap) {
fprintf (stderr, "Row: %d\tCol: %d\tValue: %-.9g\n", IntToExtRowMap [Ai [j] + 1], IntToExtColMap [i + 1], Az [j]) ;
} else {
fprintf (stderr, "Row: %d\tCol: %d\tValue: %-.9g\n", Ai [j] + 1, i + 1, Az [j]) ;
}
#endif
}
}
return 0 ;
}