int mod2sparse_decomp ( mod2sparse *A, /* Input matrix, M by N */ int K, /* Size of sub-matrix to find LU decomposition of */ mod2sparse *L, /* Matrix in which L is stored, M by K */ mod2sparse *U, /* Matrix in which U is stored, K by N */ int *rows, /* Array where row indexes are stored, M long */ int *cols, /* Array where column indexes are stored, N long */ mod2sparse_strategy strategy, /* Strategy to follow in picking rows/columns */ int abandon_number, /* Number of columns to abandon at some point */ int abandon_when /* When to abandon these columns */ ) { int *rinv=NULL, *cinv=NULL, *acnt=NULL, *rcnt=NULL; mod2sparse *B=NULL; int M, N; mod2entry *e=NULL, *f=NULL, *fn=NULL, *e2=NULL; int i=0, j=0, k=0, cc=0, cc2=0, cc3=0, cr2=0, pr=0; int found, nnf; M = mod2sparse_rows(A); N = mod2sparse_cols(A); if (mod2sparse_cols(L)!=K || mod2sparse_rows(L)!=M || mod2sparse_cols(U)!=N || mod2sparse_rows(U)!=K) { fprintf (stderr, "mod2sparse_decomp: Matrices have incompatible dimensions\n"); exit(1); } if (abandon_number>N-K) { fprintf(stderr,"Trying to abandon more columns than allowed\n"); exit(1); } rinv = (int*)chk_alloc (M, sizeof *rinv); cinv = (int*)chk_alloc (N, sizeof *cinv); if (abandon_number>0) { acnt = (int*)chk_alloc (M+1, sizeof *acnt); } if (strategy==Mod2sparse_minprod) { rcnt = (int*)chk_alloc (M, sizeof *rcnt); } mod2sparse_clear(L); mod2sparse_clear(U); /* Copy A to B. B will be modified, then discarded. */ B = mod2sparse_allocate(M,N); mod2sparse_copy(A,B); /* Count 1s in rows of B, if using minprod strategy. */ if (strategy==Mod2sparse_minprod) { for (i = 0; i<M; i++) { rcnt[i] = mod2sparse_count_row(B,i); } } /* Set up initial row and column choices. */ for (i = 0; i<M; i++) rows[i] = rinv[i] = i; for (j = 0; j<N; j++) cols[j] = cinv[j] = j; /* Find L and U one column at a time. */ nnf = 0; for (i = 0; i<K; i++) { /* Choose the next row and column of B. */ switch (strategy) { case Mod2sparse_first: { found = 0; for (k = i; k<N; k++) { e = mod2sparse_first_in_col(B,cols[k]); while (!mod2sparse_at_end(e)) { if (rinv[mod2sparse_row(e)]>=i) { found = 1; goto out_first; } e = mod2sparse_next_in_col(e); } } out_first: break; } case Mod2sparse_mincol: { found = 0; for (j = i; j<N; j++) { cc2 = mod2sparse_count_col(B,cols[j]); if (!found || cc2<cc) { e2 = mod2sparse_first_in_col(B,cols[j]); while (!mod2sparse_at_end(e2)) { if (rinv[mod2sparse_row(e2)]>=i) { found = 1; cc = cc2; e = e2; k = j; break; } e2 = mod2sparse_next_in_col(e2); } } } break; } case Mod2sparse_minprod: { found = 0; for (j = i; j<N; j++) { cc2 = mod2sparse_count_col(B,cols[j]); e2 = mod2sparse_first_in_col(B,cols[j]); while (!mod2sparse_at_end(e2)) { if (rinv[mod2sparse_row(e2)]>=i) { cr2 = rcnt[mod2sparse_row(e2)]; if (!found || cc2==1 || (cc2-1)*(cr2-1)<pr) { found = 1; pr = cc2==1 ? 0 : (cc2-1)*(cr2-1); e = e2; k = j; } } e2 = mod2sparse_next_in_col(e2); } } break; } default: { fprintf(stderr,"mod2sparse_decomp: Unknown stategy\n"); exit(1); } } if (!found) { nnf += 1; } /* Update 'rows' and 'cols'. Looks at 'k' and 'e' found above. */ if (found) { if (cinv[mod2sparse_col(e)]!=k) abort(); cols[k] = cols[i]; cols[i] = mod2sparse_col(e); cinv[cols[k]] = k; cinv[cols[i]] = i; k = rinv[mod2sparse_row(e)]; if (k<i) abort(); rows[k] = rows[i]; rows[i] = mod2sparse_row(e); rinv[rows[k]] = k; rinv[rows[i]] = i; } /* Update L, U, and B. */ f = mod2sparse_first_in_col(B,cols[i]); while (!mod2sparse_at_end(f)) { fn = mod2sparse_next_in_col(f); k = mod2sparse_row(f); if (rinv[k]>i) { mod2sparse_add_row(B,k,B,mod2sparse_row(e)); if (strategy==Mod2sparse_minprod) { rcnt[k] = mod2sparse_count_row(B,k); } mod2sparse_insert(L,k,i); } else if (rinv[k]<i) { mod2sparse_insert(U,rinv[k],cols[i]); } else { mod2sparse_insert(L,k,i); mod2sparse_insert(U,i,cols[i]); } f = fn; } /* Get rid of all entries in the current column of B, just to save space. */ for (;;) { f = mod2sparse_first_in_col(B,cols[i]); if (mod2sparse_at_end(f)) break; mod2sparse_delete(B,f); } /* Abandon columns of B with lots of entries if it's time for that. */ if (abandon_number>0 && i==abandon_when) { for (k = 0; k<M+1; k++) { acnt[k] = 0; } for (j = 0; j<N; j++) { k = mod2sparse_count_col(B,j); acnt[k] += 1; } cc = abandon_number; k = M; while (acnt[k]<cc) { cc -= acnt[k]; k -= 1; if (k<0) abort(); } cc2 = 0; for (j = 0; j<N; j++) { cc3 = mod2sparse_count_col(B,j); if (cc3>k || cc3==k && cc>0) { if (cc3==k) cc -= 1; for (;;) { f = mod2sparse_first_in_col(B,j); if (mod2sparse_at_end(f)) break; mod2sparse_delete(B,f); } cc2 += 1; } } if (cc2!=abandon_number) abort(); if (strategy==Mod2sparse_minprod) { for (j = 0; j<M; j++) { rcnt[j] = mod2sparse_count_row(B,j); } } } } /* Get rid of all entries in the rows of L past row K, after reordering. */ for (i = K; i<M; i++) { for (;;) { f = mod2sparse_first_in_row(L,rows[i]); if (mod2sparse_at_end(f)) break; mod2sparse_delete(L,f); } } mod2sparse_free(B); free(rinv); free(cinv); if (strategy==Mod2sparse_minprod) free(rcnt); if (abandon_number>0) free(acnt); return nnf; }
int main ( int argc, char **argv ) { char *alist_file, *pchk_file; FILE *af, *pf; int mxrw, mxcw; int *rw, *cw; int i, j, k; mod2entry *e; int trans; int nozeros; int last; trans = 0; nozeros = 0; for (;;) { if (argc>1 && strcmp(argv[1],"-t")==0) { trans = 1; argc -= 1; argv += 1; } else if (argc>1 && strcmp(argv[1],"-z")==0) { nozeros = 1; argc -= 1; argv += 1; } else { break; } } if (argc!=3) { usage(); } pchk_file = argv[1]; alist_file = argv[2]; read_pchk(pchk_file); if (trans) { mod2sparse *HT; HT = H; H = mod2sparse_allocate(N,M); mod2sparse_transpose(HT,H); M = mod2sparse_rows(H); N = mod2sparse_cols(H); } af = open_file_std(alist_file,"wb"); if (af==NULL) { fprintf(stderr,"Can't create alist file: %s\n",alist_file); exit(1); } fprintf(af,"%d %d\n",M,N); rw = (int *) chk_alloc (M, sizeof *rw); mxrw = 0; for (i = 0; i<M; i++) { rw[i] = mod2sparse_count_row(H,i); if (rw[i]>mxrw) { mxrw = rw[i]; } } cw = (int *) chk_alloc (N, sizeof *cw); mxcw = 0; for (j = 0; j<N; j++) { cw[j] = mod2sparse_count_col(H,j); if (cw[j]>mxcw) { mxcw = cw[j]; } } fprintf(af,"%d %d\n",mxrw,mxcw); for (i = 0; i<M; i++) { fprintf(af,"%d%c",rw[i],i==M-1?'\n':' '); } for (j = 0; j<N; j++) { fprintf(af,"%d%c",cw[j],j==N-1?'\n':' '); } for (i = 0; i<M; i++) { e = mod2sparse_first_in_row(H,i); last = 0; for (k = 0; !last; k++) { last = nozeros ? k==rw[i]-1 : k==mxrw-1; fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_col(e)+1, last?'\n':' '); if (!mod2sparse_at_end(e)) { e = mod2sparse_next_in_row(e); } } } for (j = 0; j<N; j++) { e = mod2sparse_first_in_col(H,j); last = 0; for (k = 0; !last; k++) { last = nozeros ? k==cw[j]-1 : k==mxcw-1; fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_row(e)+1, last?'\n':' '); if (!mod2sparse_at_end(e)) { e = mod2sparse_next_in_col(e); } } } if (ferror(af) || fclose(af)!=0) { fprintf(stderr,"Error writing to alist file %s\n",alist_file); exit(1); } return 0; }