home *** CD-ROM | disk | FTP | other *** search
-
- /**************************************************************************
- **
- ** Copyright (C) 1993 David E. Stewart & Zbigniew Leyk, all rights reserved.
- **
- ** Meschach Library
- **
- ** This Meschach Library is provided "as is" without any express
- ** or implied warranty of any kind with respect to this software.
- ** In particular the authors shall not be liable for any direct,
- ** indirect, special, incidental or consequential damages arising
- ** in any way from use of the software.
- **
- ** Everyone is granted permission to copy, modify and redistribute this
- ** Meschach Library, provided:
- ** 1. All copies contain this copyright notice.
- ** 2. All modified copies shall carry a notice stating who
- ** made the last modification and the date of such modification.
- ** 3. No charge is made for this software or works derived from it.
- ** This clause shall not be construed as constraining other software
- ** distributed on the same medium as this software, nor is a
- ** distribution fee considered a charge.
- **
- ***************************************************************************/
-
-
- /*
- Sparse LU factorisation
- See also: sparse.[ch] etc for details about sparse matrices
- */
-
- #include <stdio.h>
- #include <math.h>
- #include "sparse2.h"
-
-
-
- /* Macro for speedup */
- /* #define sprow_idx2(r,c,hint) \
- ( ( (hint) >= 0 && (r)->elt[hint].col == (c)) ? hint : sprow_idx((r),(c)) ) */
-
-
- /* spLUfactor -- sparse LU factorisation with pivoting
- -- uses partial pivoting and Markowitz criterion
- |a[p][k]| >= alpha * max_i |a[i][k]|
- -- creates fill-in as needed
- -- in situ factorisation */
- SPMAT *spLUfactor(A,px,alpha)
- SPMAT *A;
- PERM *px;
- double alpha;
- {
- int i, best_i, k, idx, len, best_len, m, n;
- SPROW *r, *r_piv, tmp_row;
- static SPROW *merge = (SPROW *)NULL;
- Real max_val, tmp;
- static VEC *col_vals=VNULL;
-
- if ( ! A || ! px )
- error(E_NULL,"spLUfctr");
- if ( alpha <= 0.0 || alpha > 1.0 )
- error(E_RANGE,"alpha in spLUfctr");
- if ( px->size <= A->m )
- px = px_resize(px,A->m);
- px_ident(px);
- col_vals = v_resize(col_vals,A->m);
- MEM_STAT_REG(col_vals,TYPE_VEC);
-
- m = A->m; n = A->n;
- if ( ! A->flag_col )
- sp_col_access(A);
- if ( ! A->flag_diag )
- sp_diag_access(A);
- A->flag_col = A->flag_diag = FALSE;
- if ( ! merge ) {
- merge = sprow_get(20);
- MEM_STAT_REG(merge,TYPE_SPROW);
- }
-
- for ( k = 0; k < n; k++ )
- {
- /* find pivot row/elr ( idx = 0; idx < scan_row->dim; idx++ )
- tmp_iv->ive[idx] = orig1_idx->ive[order->pe[idx]];
- iv_copy(tmp_iv,orig1_idx);
-
- s_idx = 0;
- old_col = -1;
- for ( idx = 0; idx < scan_row->dim; idx++ )
- {
- if ( col_list->ive[idx] == old_col )
- {
- if ( scan_row->ive[idx] == i )
- {
- scan_row->ive[s_idx-1] = scan_row->ive[idx];
- scan_idx->ive[s_idx-1] = scan_idx->ive[idx];
- col_list->ive[s_idx-1] = col_list->ive[idx];
- orig_idx->ive[s_idx-1] = orig_idx->ive[idx];
- orig1_idx->ive[s_idx-1] = orig1_idx->ive[idx-1];
- }
- else if ( idx > 0 )
- {
- scan_row->ive[s_idx-1] = scan_row->ive[idx-1];
- scan_idx->ive[s_idx-1] = scan_idx->ive[idx-1];
- col_list->ive[s_idx-1] = col_list->ive[idx-1];
- orig_idx->ive[s_idx-1] = orig_idx->ive[idx-1];
- orig1_idx->ive[s_idx-1] = orig1_idx->ive[idx];
- }
- }
- else
- {
- scan_row->ive[s_idx] = scan_row->ive[idx];
- scan_idx->ive[s_idx] = scan_idx->ive[idx];
- col_list->ive[s_idx] = col_list->ive[idx];
- orig_idx->ive[s_idx] = orig_idx->ive[idx];
- orig1_idx->ive[s_idx] = orig1_idx->ive[idx];
- s_idx++;
- }
- old_col = col_list->ive[idx];
- }
- scan_row = iv_resize(scan_row,s_idx);
- scan_idx = iv_resize(scan_idx,s_idx);
- col_list = iv_resize(col_list,s_idx);
- orig_idx = iv_resize(orig_idx,s_idx);
- orig1_idx = iv_resize(orig1_idx,s_idx);
-
- /* for ( j = i+2; j < n; j++ ) { .... row operation .... } */
- for ( s_idx = 0; s_idx < scan_row->dim; s_idx++ )
- {
- int idx_piv, id if ( ! r )
- return sprow_get(n);
-
- if (n == r->len)
- return r;
-
- if ( ! r->elt )
- {
- r->elt = NEW_A((unsigned)n,row_elt);
- if ( ! r->elt )
- error(E_MEM,"sprow_resize");
- else if (mem_info_is_on()) {
- mem_bytes(type,0,n*sizeof(row_elt));
- }
- r->maxlen = r->len = n;
- return r;
- }
-
- if ( n <= r->maxlen )
- r->len = n;
- else
- {
- if (mem_info_is_on()) {
- mem_bytes(type,r->maxlen*sizeof(row_elt),
- n*sizeof(row_elt));
- }
- r->elt = RENEW(r->elt,n,row_elt);
- if ( ! r->elt )
- error(E_MEM,"sprow_resize");
- r->maxlen = r->len = n;
- }
-
- return r;
- }
-
-
- /* release a row of a matrix */
- int sprow_free(r)
- SPROW *r;
- {
- if ( ! r )
- return -1;
-
- if (mem_info_is_on()) {
- mem_bytes(TYPE_SPROW,sizeof(SPROW),0);
- mem_numvar(TYPE_SPROW,-1);
- }
-
- if ( r->elt )
- {
- if (mem_info_is_on()) {
- mem_bytes(TYPE_SPROW,r->maxlen*sizeof(row_elt),0);
- }
- free((char *)r->elt);
- }
- free((char *)r);
- return 0;
- }
-
-
- /* sprow_merge -- merges r1 and r2 into r_out
- -- cannot be done in-situ
- -- type must be SPMAT or SPROW depending on
- whether r_out is a row of a SPMAT structure
- or a SPROW variable
- -- returns r_out */
- SPROW *sprow_merge(r1,r2,r_out,type)
- SPROW *r1, *r2, *r_out;
- int type;
- {
- int idx1, idx2, idx_out, len1, len2, len_out;
- row_elt *elt1, *elt2, *elt_out;
-
- if ( ! r1 || ! r2 )
- error(E_NULL,"sprow_merge");
- if ( ! r_out )
- r_out = sprow_get(MINROWLEN);
- if ( r1 == r_out || r2 == r_out )
- error(E_INSITU,"sprow_merge");
-
- /* Initialise */
- len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
- idx1 = idx2 = idx_out = 0;
- elt1 = r1->elt; elt2 = r2->elt; elt_out = r_out->elt;
-
- while ( idx1 < len1 || idx2 < len2 )
- {
- if ( idx_out >= len_out )
- { /* r_out is too small */
- r_out->len = idx_out;
- r_out = sprow_xpd(r_out,0,type);
- len_out = r_out->len;
- elt_out = &(r_out->elt[idx_out]);
- }
- if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
- {
- elt_out->col = elt1->col;
- elt_out->val = elt1->val;
- if ( elt1->col == elt2->col && idx2 < len2 )
- { elt2++; idx2++; }
- elt1++; idx1++;
- }
- else
- {
- elt_out->col = elt2->col;
- elt_out->val = elt2->val;
- elt2++; idx2++;
- }
- elt_out++; idx_out++;
- }
- r_out->len = idx_out;
-
- return r_out;
- }
-
- /* sprow_copy -- copies r1 and r2 into r_out
- -- cannot be done in-situ
- -- type must be SPMAT or SPROW depending on
- whether r_out is a row of a SPMAT structure
- or a SPROW variable
- -- returns r_out */
- SPROW *sprow_copy(r1,r2,r_out,type)
- SPROW *r1, *r2, *r_out;
- int type;
- {
- int idx1, idx2, idx_out, len1, len2, len_out;
- row_elt *elt1, *elt2, *elt_out;
-
- if ( ! r1 || ! r2 )
- error(E_NULL,"sprow_copy");
- if ( ! r_out )
- r_out = sprow_get(MINROWLEN);
- if ( r1 == r_out || r2 == r_out )
- error(E_INSITU,"sprow_copy");
-
- /* Initialise */
- len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
- idx1 = idx2 = idx_out = 0;
- elt1 = r1->elt; elt2 = r2->elt; elt_out = r_out->elt;
-
- while ( idx1 < len1 || idx2 < len2 )
- {
- while ( idx_out >= len_out )
- { /* r_out is too small */
- r_out->len = idx_out;
- r_out = sprow_xpd(r_out,0,type);
- len_out = r_out->maxlen;
- elt_out = &(r_out->elt[idx_out]);
- }
- if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
- {
- elt_out->col = elt1->col;
- elt_out->val = elt1->val;
- if ( elt1->col == elt2->col && idx2 < len2 )
- { elt2++; idx2++; }
- elt1++; idx1++;
- }
- else
- {
- elt_out->col = elt2->col;
- elt_out->val = 0.0;
- elt2++; idx2++;
- }
- elt_out++; idx_out++;
- }
- r_out->len = idx_out;
-
- return r_out;
- }
-
- /* sprow_mltadd -- sets r_out <- r1 + alpha.r2
- -- cannot be in situ
- -- only for columns j0, j0+1, ...
- -- type must be SPMAT or SPROW depending on
- whether r_out is a row of a SPMAT structure
- or a SPROW variable
- -- returns r_out */
- SPROW *sprow_mltadd(r1,r2,alpha,j0,r_out,type)
- SPROW *r1, *r2, *r_out;
- double alpha;
- int j0, type;
- {
- int idx1, idx2, idx_out, len1, len2, len_out;
- row_elt *elt1, *elt2, *elt_out;
-
- if ( ! r1 || ! r2 )
- error(E_NULL,"sprow_mltadd");
- if ( r1 == r_out || r2 == r_out )
- error(E_INSITU,"sprow_mltadd");
- if ( j0 < 0 )
- error(E_BOUNDS,"sprow_mltadd");
- if ( ! r_out )
- r_out = sprow_get(MINROWLEN);
-
- /* Initialise */
- len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
- /* idx1 = idx2 = idx_out = 0; */
- idx1 = sprow_idx(r1,j0);
- idx2 = sprow_idx(r2,j0);
- idx_out = sprow_idx(r_out,j0);
- idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
- idx2 = (idx2 < 0) ? -(idx2+2) : idx2;
- idx_out = (idx_out < 0) ? -(idx_out+2) : idx_out;
- elt1 = &(r1->elt[idx1]);
- elt2 = &(r2->elt[idx2]);
- elt_out = &(r_out->elt[idx_out]);
-
- while ( idx1 < len1 || idx2 < len2 )
- {
- if ( idx_out >= len_out )
- { /* r_out is too small */
- r_out->len = idx_out;
- r_out = sprow_xpd(r_out,0,type);
- len_out = r_out->maxlen;
- elt_out = &(r_out->elt[idx_out]);
- }
- if ( idx2 >= len2 || (idx1 < len1 && elt1->col <= elt2->col) )
- {
- elt_out->col = elt1->col;
- elt_out->val = elt1->val;
- if ( idx2 < len2 && elt1->col == elt2->col )
- {
- elt_out->val += alpha*elt2->val;
- elt2++; idx2++;
- }
- elt1++; idx1++;
- }
- else
- {
- elt_out->col = elt2->col;
- elt_out->val = alpha*elt2->val;
- elt2++; idx2++;
- }
- elt_out++; idx_out++;
- }
- r_out->len = idx_out;
-
- return r_out;
- }
-
- /* sprow_add -- sets r_out <- r1 + r2
- -- cannot be in situ
- -- only for columns j0, j0+1, ...
- -- type must be SPMAT or SPROW depending on
- whether r_out is a row of a SPMAT structure
- or a SPROW variable
- -- returns r_out */
- SPROW *sprow_add(r1,r2,j0,r_out,type)
- SPROW *r1, *r2, *r_out;
- int j0, type;
- {
- int idx1, idx2, idx_out, len1, len2, len_out;
- row_elt *elt1, *elt2, *elt_out;
-
- if ( ! r1 || ! r2 )
- error(E_NULL,"sprow_add");
- if ( r1 == r_out || r2 == r_out )
- error(E_INSITU,"sprow_add");
- if ( j0 < 0 )
- error(E_BOUNDS,"sprow_add");
- if ( ! r_out )
- r_out = sprow_get(MINROWLEN);
-
- /* Initialise */
- len1 = r1->len; len2 = r2->len; len_out = r_out->maxlen;
- /* idx1 = idx2 = idx_out = 0; */
- idx1 = sprow_idx(r1,j0);
- idx2 = sprow_idx(r2,j0);
- idx_out = sprow_idx(r_out,j0);
- idx1 = (idx1 < 0) ? -(idx1+2) : idx1;
- idx2 = (idx2 < 0) ? -(idx2+2) : idx2;
- idx_out = (idx_out < 0) ? -(idx_out+2) : idx_out;
- elt1 = &(r1->elt[idx1]);
- elt2 = &(r2->elt[idx2]);
- elt_out = &(r_out->elt[idx_out]);
-
- while ( idx1 < len1 || idx2 < len2 )
- {
- if ( idx_out >= len_out )
- { /* r_out is too small