/************************************************************************** ** ** Copyright (C) 1993 David E. Steward & 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 matrix package See also: sparse.h, matrix.h */ #include #include #include #include "sparse.h" static char rcsid[] = "$Id: sparse.c,v 1.2 1999/06/04 21:52:19 soliday Exp $"; #define MINROWLEN 10 /* sp_get_val -- returns the (i,j) entry of the sparse matrix A */ double sp_get_val(A,i,j) SPMAT *A; int i, j; { SPROW *r; int idx; if ( A == SMNULL ) error(E_NULL,"sp_get_val"); if ( i < 0 || i >= A->m || j < 0 || j >= A->n ) error(E_SIZES,"sp_get_val"); r = A->row+i; idx = sprow_idx(r,j); if ( idx < 0 ) return 0.0; /* else */ return r->elt[idx].val; } /* sp_set_val -- sets the (i,j) entry of the sparse matrix A */ double sp_set_val(A,i,j,val) SPMAT *A; int i, j; double val; { SPROW *r; int idx, idx2, new_len; if ( A == SMNULL ) error(E_NULL,"sp_set_val"); if ( i < 0 || i >= A->m || j < 0 || j >= A->n ) error(E_SIZES,"sp_set_val"); r = A->row+i; idx = sprow_idx(r,j); /* printf("sp_set_val: idx = %d\n",idx); */ if ( idx >= 0 ) { r->elt[idx].val = val; return val; } /* else */ if ( idx < -1 ) { /* Note: this destroys the column & diag access paths */ A->flag_col = A->flag_diag = FALSE; /* shift & insert new value */ idx = -(idx+2); /* this is the intended insertion index */ if ( r->len >= r->maxlen ) { r->len = r->maxlen; new_len = max(2*r->maxlen+1,5); if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,A->row[i].maxlen*sizeof(row_elt), new_len*sizeof(row_elt)); } r->elt = RENEW(r->elt,new_len,row_elt); if ( ! r->elt ) /* can't allocate */ error(E_MEM,"sp_set_val"); r->maxlen = 2*r->maxlen+1; } for ( idx2 = r->len-1; idx2 >= idx; idx2-- ) MEM_COPY((char *)(&(r->elt[idx2])), (char *)(&(r->elt[idx2+1])),sizeof(row_elt)); /************************************************************ if ( idx < r->len ) MEM_COPY((char *)(&(r->elt[idx])),(char *)(&(r->elt[idx+1])), (r->len-idx)*sizeof(row_elt)); ************************************************************/ r->len++; r->elt[idx].col = j; return r->elt[idx].val = val; } /* else -- idx == -1, error in index/matrix! */ return 0.0; } /* sp_mv_mlt -- sparse matrix/dense vector multiply -- result is in out, which is returned unless out==NULL on entry -- if out==NULL on entry then the result vector is created */ VEC *sp_mv_mlt(A,x,out) SPMAT *A; VEC *x, *out; { int i, j_idx, m, n, max_idx; Real sum, *x_ve; SPROW *r; row_elt *elts; if ( ! A || ! x ) error(E_NULL,"sp_mv_mlt"); if ( x->dim != A->n ) error(E_SIZES,"sp_mv_mlt"); if ( ! out || out->dim < A->m ) out = v_resize(out,A->m); if ( out == x ) error(E_INSITU,"sp_mv_mlt"); m = A->m; n = A->n; x_ve = x->ve; for ( i = 0; i < m; i++ ) { sum = 0.0; r = &(A->row[i]); max_idx = r->len; elts = r->elt; for ( j_idx = 0; j_idx < max_idx; j_idx++, elts++ ) sum += elts->val*x_ve[elts->col]; out->ve[i] = sum; } return out; } /* sp_vm_mlt -- sparse matrix/dense vector multiply from left -- result is in out, which is returned unless out==NULL on entry -- if out==NULL on entry then result vector is created & returned */ VEC *sp_vm_mlt(A,x,out) SPMAT *A; VEC *x, *out; { int i, j_idx, m, n, max_idx; Real tmp, *x_ve, *out_ve; SPROW *r; row_elt *elts; if ( ! A || ! x ) error(E_NULL,"sp_vm_mlt"); if ( x->dim != A->m ) error(E_SIZES,"sp_vm_mlt"); if ( ! out || out->dim < A->n ) out = v_resize(out,A->n); if ( out == x ) error(E_INSITU,"sp_vm_mlt"); m = A->m; n = A->n; v_zero(out); x_ve = x->ve; out_ve = out->ve; for ( i = 0; i < m; i++ ) { r = A->row+i; max_idx = r->len; elts = r->elt; tmp = x_ve[i]; for ( j_idx = 0; j_idx < max_idx; j_idx++, elts++ ) out_ve[elts->col] += elts->val*tmp; } return out; } /* sp_get -- get sparse matrix -- len is number of elements available for each row without allocating further memory */ SPMAT *sp_get(m,n,maxlen) int m, n, maxlen; { SPMAT *A; SPROW *rows; int i; if ( m < 0 || n < 0 ) error(E_NEG,"sp_get"); maxlen = max(maxlen,1); A = NEW(SPMAT); if ( ! A ) /* can't allocate */ error(E_MEM,"sp_get"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,sizeof(SPMAT)); mem_numvar(TYPE_SPMAT,1); } /* fprintf(stderr,"Have SPMAT structure\n"); */ A->row = rows = NEW_A(m,SPROW); if ( ! A->row ) /* can't allocate */ error(E_MEM,"sp_get"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,m*sizeof(SPROW)); } /* fprintf(stderr,"Have row structure array\n"); */ A->start_row = NEW_A(n,int); A->start_idx = NEW_A(n,int); if ( ! A->start_row || ! A->start_idx ) /* can't allocate */ error(E_MEM,"sp_get"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,2*n*sizeof(int)); } for ( i = 0; i < n; i++ ) A->start_row[i] = A->start_idx[i] = -1; /* fprintf(stderr,"Have start_row array\n"); */ A->m = A->max_m = m; A->n = A->max_n = n; for ( i = 0; i < m; i++, rows++ ) { rows->elt = NEW_A(maxlen,row_elt); if ( ! rows->elt ) error(E_MEM,"sp_get"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,maxlen*sizeof(row_elt)); } /* fprintf(stderr,"Have row %d element array\n",i); */ rows->len = 0; rows->maxlen = maxlen; rows->diag = -1; } return A; } /* sp_free -- frees up the memory for a sparse matrix */ int sp_free(A) SPMAT *A; { SPROW *r; int i; if ( ! A ) return -1; if ( A->start_row != (int *)NULL ) { if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,A->max_n*sizeof(int),0); } free((char *)(A->start_row)); } if ( A->start_idx != (int *)NULL ) { if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,A->max_n*sizeof(int),0); } free((char *)(A->start_idx)); } if ( ! A->row ) { if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,sizeof(SPMAT),0); mem_numvar(TYPE_SPMAT,-1); } free((char *)A); return 0; } for ( i = 0; i < A->m; i++ ) { r = &(A->row[i]); if ( r->elt != (row_elt *)NULL ) { if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,A->row[i].maxlen*sizeof(row_elt),0); } free((char *)(r->elt)); } } if (mem_info_is_on()) { if (A->row) mem_bytes(TYPE_SPMAT,A->max_m*sizeof(SPROW),0); mem_bytes(TYPE_SPMAT,sizeof(SPMAT),0); mem_numvar(TYPE_SPMAT,-1); } free((char *)(A->row)); free((char *)A); return 0; } /* sp_copy -- constructs a copy of a given matrix -- note that the max_len fields (etc) are no larger in the copy than necessary -- result is returned */ SPMAT *sp_copy(A) SPMAT *A; { SPMAT *out; SPROW *row1, *row2; int i; if ( A == SMNULL ) error(E_NULL,"sp_copy"); if ( ! (out=NEW(SPMAT)) ) error(E_MEM,"sp_copy"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,sizeof(SPMAT)); mem_numvar(TYPE_SPMAT,1); } out->m = out->max_m = A->m; out->n = out->max_n = A->n; /* set up rows */ if ( ! (out->row=NEW_A(A->m,SPROW)) ) error(E_MEM,"sp_copy"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,A->m*sizeof(SPROW)); } for ( i = 0; i < A->m; i++ ) { row1 = &(A->row[i]); row2 = &(out->row[i]); if ( ! (row2->elt=NEW_A(max(row1->len,3),row_elt)) ) error(E_MEM,"sp_copy"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,max(row1->len,3)*sizeof(row_elt)); } row2->len = row1->len; row2->maxlen = max(row1->len,3); row2->diag = row1->diag; MEM_COPY((char *)(row1->elt),(char *)(row2->elt), row1->len*sizeof(row_elt)); } /* set up start arrays -- for column access */ if ( ! (out->start_idx=NEW_A(A->n,int)) || ! (out->start_row=NEW_A(A->n,int)) ) error(E_MEM,"sp_copy"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,2*A->n*sizeof(int)); } MEM_COPY((char *)(A->start_idx),(char *)(out->start_idx), A->n*sizeof(int)); MEM_COPY((char *)(A->start_row),(char *)(out->start_row), A->n*sizeof(int)); return out; } /* sp_col_access -- set column access path; i.e. nxt_row, nxt_idx fields -- returns A */ SPMAT *sp_col_access(A) SPMAT *A; { int i, j, j_idx, len, m, n; SPROW *row; row_elt *r_elt; int *start_row, *start_idx; if ( A == SMNULL ) error(E_NULL,"sp_col_access"); m = A->m; n = A->n; /* initialise start_row and start_idx */ start_row = A->start_row; start_idx = A->start_idx; for ( j = 0; j < n; j++ ) { *start_row++ = -1; *start_idx++ = -1; } start_row = A->start_row; start_idx = A->start_idx; /* now work UP the rows, setting nxt_row, nxt_idx fields */ for ( i = m-1; i >= 0; i-- ) { row = &(A->row[i]); r_elt = row->elt; len = row->len; for ( j_idx = 0; j_idx < len; j_idx++, r_elt++ ) { j = r_elt->col; r_elt->nxt_row = start_row[j]; r_elt->nxt_idx = start_idx[j]; start_row[j] = i; start_idx[j] = j_idx; } } A->flag_col = TRUE; return A; } /* sp_diag_access -- set diagonal access path(s) */ SPMAT *sp_diag_access(A) SPMAT *A; { int i, m; SPROW *row; if ( A == SMNULL ) error(E_NULL,"sp_diag_access"); m = A->m; row = A->row; for ( i = 0; i < m; i++, row++ ) row->diag = sprow_idx(row,i); A->flag_diag = TRUE; return A; } /* sp_m2dense -- convert a sparse matrix to a dense one */ MAT *sp_m2dense(A,out) SPMAT *A; MAT *out; { int i, j_idx; SPROW *row; row_elt *elt; if ( ! A ) error(E_NULL,"sp_m2dense"); if ( ! out || out->m < A->m || out->n < A->n ) out = m_get(A->m,A->n); m_zero(out); for ( i = 0; i < A->m; i++ ) { row = &(A->row[i]); elt = row->elt; for ( j_idx = 0; j_idx < row->len; j_idx++, elt++ ) out->me[i][elt->col] = elt->val; } return out; } /* C = A+B, can be in situ */ SPMAT *sp_add(A,B,C) SPMAT *A, *B, *C; { int i, in_situ; SPROW *rc; static SPROW *tmp; if ( ! A || ! B ) error(E_NULL,"sp_add"); if ( A->m != B->m || A->n != B->n ) error(E_SIZES,"sp_add"); if (C == A || C == B) in_situ = TRUE; else in_situ = FALSE; if ( ! C ) C = sp_get(A->m,A->n,5); else { if ( C->m != A->m || C->n != A->n ) error(E_SIZES,"sp_add"); if (!in_situ) sp_zero(C); } if (tmp == (SPROW *)NULL && in_situ) { tmp = sprow_get(MINROWLEN); MEM_STAT_REG(tmp,TYPE_SPROW); } if (in_situ) for (i=0; i < A->m; i++) { rc = &(C->row[i]); sprow_add(&(A->row[i]),&(B->row[i]),0,tmp,TYPE_SPROW); sprow_resize(rc,tmp->len,TYPE_SPMAT); MEM_COPY(tmp->elt,rc->elt,tmp->len*sizeof(row_elt)); rc->len = tmp->len; } else for (i=0; i < A->m; i++) { sprow_add(&(A->row[i]),&(B->row[i]),0,&(C->row[i]),TYPE_SPMAT); } C->flag_col = C->flag_diag = FALSE; return C; } /* C = A-B, cannot be in situ */ SPMAT *sp_sub(A,B,C) SPMAT *A, *B, *C; { int i, in_situ; SPROW *rc; static SPROW *tmp; if ( ! A || ! B ) error(E_NULL,"sp_sub"); if ( A->m != B->m || A->n != B->n ) error(E_SIZES,"sp_sub"); if (C == A || C == B) in_situ = TRUE; else in_situ = FALSE; if ( ! C ) C = sp_get(A->m,A->n,5); else { if ( C->m != A->m || C->n != A->n ) error(E_SIZES,"sp_sub"); if (!in_situ) sp_zero(C); } if (tmp == (SPROW *)NULL && in_situ) { tmp = sprow_get(MINROWLEN); MEM_STAT_REG(tmp,TYPE_SPROW); } if (in_situ) for (i=0; i < A->m; i++) { rc = &(C->row[i]); sprow_sub(&(A->row[i]),&(B->row[i]),0,tmp,TYPE_SPROW); sprow_resize(rc,tmp->len,TYPE_SPMAT); MEM_COPY(tmp->elt,rc->elt,tmp->len*sizeof(row_elt)); rc->len = tmp->len; } else for (i=0; i < A->m; i++) { sprow_sub(&(A->row[i]),&(B->row[i]),0,&(C->row[i]),TYPE_SPMAT); } C->flag_col = C->flag_diag = FALSE; return C; } /* C = A+alpha*B, cannot be in situ */ SPMAT *sp_mltadd(A,B,alpha,C) SPMAT *A, *B, *C; double alpha; { int i, in_situ; SPROW *rc; static SPROW *tmp; if ( ! A || ! B ) error(E_NULL,"sp_mltadd"); if ( A->m != B->m || A->n != B->n ) error(E_SIZES,"sp_mltadd"); if (C == A || C == B) in_situ = TRUE; else in_situ = FALSE; if ( ! C ) C = sp_get(A->m,A->n,5); else { if ( C->m != A->m || C->n != A->n ) error(E_SIZES,"sp_mltadd"); if (!in_situ) sp_zero(C); } if (tmp == (SPROW *)NULL && in_situ) { tmp = sprow_get(MINROWLEN); MEM_STAT_REG(tmp,TYPE_SPROW); } if (in_situ) for (i=0; i < A->m; i++) { rc = &(C->row[i]); sprow_mltadd(&(A->row[i]),&(B->row[i]),alpha,0,tmp,TYPE_SPROW); sprow_resize(rc,tmp->len,TYPE_SPMAT); MEM_COPY(tmp->elt,rc->elt,tmp->len*sizeof(row_elt)); rc->len = tmp->len; } else for (i=0; i < A->m; i++) { sprow_mltadd(&(A->row[i]),&(B->row[i]),alpha,0, &(C->row[i]),TYPE_SPMAT); } C->flag_col = C->flag_diag = FALSE; return C; } /* B = alpha*A, can be in situ */ SPMAT *sp_smlt(A,alpha,B) SPMAT *A, *B; double alpha; { int i; if ( ! A ) error(E_NULL,"sp_smlt"); if ( ! B ) B = sp_get(A->m,A->n,5); else if ( A->m != B->m || A->n != B->n ) error(E_SIZES,"sp_smlt"); for (i=0; i < A->m; i++) { sprow_smlt(&(A->row[i]),alpha,0,&(B->row[i]),TYPE_SPMAT); } return B; } /* sp_zero -- zero all the (represented) elements of a sparse matrix */ SPMAT *sp_zero(A) SPMAT *A; { int i, idx, len; row_elt *elt; if ( ! A ) error(E_NULL,"sp_zero"); for ( i = 0; i < A->m; i++ ) { elt = A->row[i].elt; len = A->row[i].len; for ( idx = 0; idx < len; idx++ ) (*elt++).val = 0.0; } return A; } /* sp_copy2 -- copy sparse matrix (type 2) -- keeps structure of the OUT matrix */ SPMAT *sp_copy2(A,OUT) SPMAT *A, *OUT; { int i /* , idx, len1, len2 */; SPROW *r1, *r2; static SPROW *scratch = (SPROW *)NULL; /* row_elt *e1, *e2; */ if ( ! A ) error(E_NULL,"sp_copy2"); if ( ! OUT ) OUT = sp_get(A->m,A->n,10); if ( ! scratch ) { scratch = sprow_xpd(scratch,MINROWLEN,TYPE_SPROW); MEM_STAT_REG(scratch,TYPE_SPROW); } if ( OUT->m < A->m ) { if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,A->max_m*sizeof(SPROW), A->m*sizeof(SPROW)); } OUT->row = RENEW(OUT->row,A->m,SPROW); if ( ! OUT->row ) error(E_MEM,"sp_copy2"); for ( i = OUT->m; i < A->m; i++ ) { OUT->row[i].elt = NEW_A(MINROWLEN,row_elt); if ( ! OUT->row[i].elt ) error(E_MEM,"sp_copy2"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,MINROWLEN*sizeof(row_elt)); } OUT->row[i].maxlen = MINROWLEN; OUT->row[i].len = 0; } OUT->m = A->m; } OUT->flag_col = OUT->flag_diag = FALSE; /* sp_zero(OUT); */ for ( i = 0; i < A->m; i++ ) { r1 = &(A->row[i]); r2 = &(OUT->row[i]); sprow_copy(r1,r2,scratch,TYPE_SPROW); if ( r2->maxlen < scratch->len ) sprow_xpd(r2,scratch->len,TYPE_SPMAT); MEM_COPY((char *)(scratch->elt),(char *)(r2->elt), scratch->len*sizeof(row_elt)); r2->len = scratch->len; /******************************************************* e1 = r1->elt; e2 = r2->elt; len1 = r1->len; len2 = r2->len; for ( idx = 0; idx < len2; idx++, e2++ ) e2->val = 0.0; for ( idx = 0; idx < len1; idx++, e1++ ) sprow_set_val(r2,e1->col,e1->val); *******************************************************/ } sp_col_access(OUT); return OUT; } /* sp_resize -- resize a sparse matrix -- don't destroying any contents if possible -- returns resized matrix */ SPMAT *sp_resize(A,m,n) SPMAT *A; int m, n; { int i, len; SPROW *r; if (m < 0 || n < 0) error(E_NEG,"sp_resize"); if ( ! A ) return sp_get(m,n,10); if (m == A->m && n == A->n) return A; if ( m <= A->max_m ) { for ( i = A->m; i < m; i++ ) A->row[i].len = 0; A->m = m; } else { if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,A->max_m*sizeof(SPROW), m*sizeof(SPROW)); } A->row = RENEW(A->row,(unsigned)m,SPROW); if ( ! A->row ) error(E_MEM,"sp_resize"); for ( i = A->m; i < m; i++ ) { if ( ! (A->row[i].elt = NEW_A(MINROWLEN,row_elt)) ) error(E_MEM,"sp_resize"); else if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,0,MINROWLEN*sizeof(row_elt)); } A->row[i].len = 0; A->row[i].maxlen = MINROWLEN; } A->m = A->max_m = m; } /* update number of rows */ A->n = n; /* do we need to increase the size of start_idx[] and start_row[] ? */ if ( n > A->max_n ) { /* only have to update the start_idx & start_row arrays */ if (mem_info_is_on()) { mem_bytes(TYPE_SPMAT,2*A->max_n*sizeof(int), 2*n*sizeof(int)); } A->start_row = RENEW(A->start_row,(unsigned)n,int); A->start_idx = RENEW(A->start_idx,(unsigned)n,int); if ( ! A->start_row || ! A->start_idx ) error(E_MEM,"sp_resize"); A->max_n = n; /* ...and update max_n */ return A; } if ( n <= A->n ) /* make sure that all rows are truncated just before column n */ for ( i = 0; i < A->m; i++ ) { r = &(A->row[i]); len = sprow_idx(r,n); if ( len < 0 ) len = -(len+2); if ( len < 0 ) error(E_MEM,"sp_resize"); r->len = len; } return A; } /* sp_compact -- removes zeros and near-zeros from a sparse matrix */ SPMAT *sp_compact(A,tol) SPMAT *A; double tol; { int i, idx1, idx2; SPROW *r; row_elt *elt1, *elt2; if ( ! A ) error(E_NULL,"sp_compact"); if ( tol < 0.0 ) error(E_RANGE,"sp_compact"); A->flag_col = A->flag_diag = FALSE; for ( i = 0; i < A->m; i++ ) { r = &(A->row[i]); elt1 = elt2 = r->elt; idx1 = idx2 = 0; while ( idx1 < r->len ) { /* printf("# sp_compact: idx1 = %d, idx2 = %d\n",idx1,idx2); */ if ( fabs(elt1->val) <= tol ) { idx1++; elt1++; continue; } if ( elt1 != elt2 ) MEM_COPY(elt1,elt2,sizeof(row_elt)); idx1++; elt1++; idx2++; elt2++; } r->len = idx2; } return A; } /* varying number of arguments */ #ifdef ANSI_C /* To allocate memory to many arguments. The function should be called: sp_get_vars(m,n,deg,&x,&y,&z,...,NULL); where int m,n,deg; SPMAT *x, *y, *z,...; The last argument should be NULL ! m x n is the dimension of matrices x,y,z,... returned value is equal to the number of allocated variables */ int sp_get_vars(int m,int n,int deg,...) { va_list ap; int i=0; SPMAT **par; va_start(ap, deg); while ((par = va_arg(ap,SPMAT **))) { /* NULL ends the list*/ *par = sp_get(m,n,deg); i++; } va_end(ap); return i; } /* To resize memory for many arguments. The function should be called: sp_resize_vars(m,n,&x,&y,&z,...,NULL); where int m,n; SPMAT *x, *y, *z,...; The last argument should be NULL ! m X n is the resized dimension of matrices x,y,z,... returned value is equal to the number of allocated variables. If one of x,y,z,.. arguments is NULL then memory is allocated to this argument. */ int sp_resize_vars(int m,int n,...) { va_list ap; int i=0; SPMAT **par; va_start(ap, n); while ((par = va_arg(ap,SPMAT **))) { /* NULL ends the list*/ *par = sp_resize(*par,m,n); i++; } va_end(ap); return i; } /* To deallocate memory for many arguments. The function should be called: sp_free_vars(&x,&y,&z,...,NULL); where SPMAT *x, *y, *z,...; The last argument should be NULL ! There must be at least one not NULL argument. returned value is equal to the number of allocated variables. Returned value of x,y,z,.. is VNULL. */ int sp_free_vars(SPMAT **va,...) { va_list ap; int i=1; SPMAT **par; sp_free(*va); *va = (SPMAT *) NULL; va_start(ap, va); while ((par = va_arg(ap,SPMAT **))) { /* NULL ends the list*/ sp_free(*par); *par = (SPMAT *)NULL; i++; } va_end(ap); return i; } #elif VARARGS /* To allocate memory to many arguments. The function should be called: sp_get_vars(m,n,deg,&x,&y,&z,...,NULL); where int m,n,deg; SPMAT *x, *y, *z,...; The last argument should be NULL ! m x n is the dimension of matrices x,y,z,... returned value is equal to the number of allocated variables */ int sp_get_vars(va_alist) va_dcl { va_list ap; int i=0, m, n, deg; SPMAT **par; va_start(ap); m = va_arg(ap,int); n = va_arg(ap,int); deg = va_arg(ap,int); while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/ *par = sp_get(m,n,deg); i++; } va_end(ap); return i; } /* To resize memory for many arguments. The function should be called: sp_resize_vars(m,n,&x,&y,&z,...,NULL); where int m,n; SPMAT *x, *y, *z,...; The last argument should be NULL ! m X n is the resized dimension of matrices x,y,z,... returned value is equal to the number of allocated variables. If one of x,y,z,.. arguments is NULL then memory is allocated to this argument. */ int sp_resize_vars(va_alist) va_dcl { va_list ap; int i=0, m, n; SPMAT **par; va_start(ap); m = va_arg(ap,int); n = va_arg(ap,int); while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/ *par = sp_resize(*par,m,n); i++; } va_end(ap); return i; } /* To deallocate memory for many arguments. The function should be called: sp_free_vars(&x,&y,&z,...,NULL); where SPMAT *x, *y, *z,...; The last argument should be NULL ! There must be at least one not NULL argument. returned value is equal to the number of allocated variables. Returned value of x,y,z,.. is VNULL. */ int sp_free_vars(va_alist) va_dcl { va_list ap; int i=0; SPMAT **par; va_start(ap); while (par = va_arg(ap,SPMAT **)) { /* NULL ends the list*/ sp_free(*par); *par = (SPMAT *)NULL; i++; } va_end(ap); return i; } #endif