void mod2sparse_transpose ( mod2sparse *m, /* Matrix to compute transpose of (left unchanged) */ mod2sparse *r /* Result of transpose operation */ ) { mod2entry *e; int i; if (mod2sparse_rows(m)!=mod2sparse_cols(r) || mod2sparse_cols(m)!=mod2sparse_rows(r)) { fprintf(stderr, "mod2sparse_transpose: Matrices have incompatible dimensions\n"); exit(1); } if (r==m) { fprintf(stderr, "mod2sparse_transpose: Result matrix is the same as the operand\n"); exit(1); } mod2sparse_clear(r); for (i = 0; i<mod2sparse_rows(m); i++) { e = mod2sparse_first_in_row(m,i); while (!mod2sparse_at_end(e)) { mod2sparse_insert(r,mod2sparse_col(e),i); e = mod2sparse_next_in_row(e); } } }
void mod2sparse_copy ( mod2sparse *m, /* Matrix to copy */ mod2sparse *r /* Place to store copy of matrix */ ) { mod2entry *e, *f; int i; if (mod2sparse_rows(m)>mod2sparse_rows(r) || mod2sparse_cols(m)>mod2sparse_cols(r)) { fprintf(stderr,"mod2sparse_copy: Destination matrix is too small\n"); exit(1); } mod2sparse_clear(r); for (i = 0; i<mod2sparse_rows(m); i++) { e = mod2sparse_first_in_row(m,i); while (!mod2sparse_at_end(e)) { f = mod2sparse_insert(r,e->row,e->col); #if 0 f->lr = e->lr; f->pr = e->pr; #endif e = mod2sparse_next_in_row(e); } } }
void mod2sparse_copycols ( mod2sparse *m, /* Matrix to copy */ mod2sparse *r, /* Place to store copy of matrix */ int *cols /* Indexes of columns to copy, from 0 */ ) { mod2entry *e; int j; if (mod2sparse_rows(m)>mod2sparse_rows(r)) { fprintf(stderr, "mod2sparse_copycols: Destination matrix has fewer rows than source\n"); exit(1); } mod2sparse_clear(r); for (j = 0; j<mod2sparse_cols(r); j++) { if (cols[j]<0 || cols[j]>=mod2sparse_cols(m)) { fprintf(stderr,"mod2sparse_copycols: Column index out of range\n"); exit(1); } e = mod2sparse_first_in_col(m,cols[j]); while (!mod2sparse_at_end(e)) { mod2sparse_insert(r,e->row,j); e = mod2sparse_next_in_col(e); } } }
void mod2sparse_copyrows ( mod2sparse *m, /* Matrix to copy */ mod2sparse *r, /* Place to store copy of matrix */ int *rows /* Indexes of rows to copy, from 0 */ ) { mod2entry *e; int i; if (mod2sparse_cols(m)>mod2sparse_cols(r)) { fprintf(stderr, "mod2sparse_copyrows: Destination matrix has fewer columns than source\n"); exit(1); } mod2sparse_clear(r); for (i = 0; i<mod2sparse_rows(r); i++) { if (rows[i]<0 || rows[i]>=mod2sparse_rows(m)) { fprintf(stderr,"mod2sparse_copyrows: Row index out of range\n"); exit(1); } e = mod2sparse_first_in_row(m,rows[i]); while (!mod2sparse_at_end(e)) { mod2sparse_insert(r,i,e->col); e = mod2sparse_next_in_row(e); } } }
void mod2sparse_add ( mod2sparse *m1, /* Left operand of add */ mod2sparse *m2, /* Right operand of add */ mod2sparse *r /* Place to store result of add */ ) { mod2entry *e1, *e2; int i; if (mod2sparse_rows(m1)!=mod2sparse_rows(r) || mod2sparse_cols(m1)!=mod2sparse_cols(r) || mod2sparse_rows(m2)!=mod2sparse_rows(r) || mod2sparse_cols(m2)!=mod2sparse_cols(r)) { fprintf(stderr,"mod2sparse_add: Matrices have different dimensions\n"); exit(1); } if (r==m1 || r==m2) { fprintf(stderr, "mod2sparse_add: Result matrix is the same as one of the operands\n"); exit(1); } mod2sparse_clear(r); for (i = 0; i<mod2sparse_rows(r); i++) { e1 = mod2sparse_first_in_row(m1,i); e2 = mod2sparse_first_in_row(m2,i); while (!mod2sparse_at_end(e1) && !mod2sparse_at_end(e2)) { if (mod2sparse_col(e1)==mod2sparse_col(e2)) { e1 = mod2sparse_next_in_row(e1); e2 = mod2sparse_next_in_row(e2); } else if (mod2sparse_col(e1)<mod2sparse_col(e2)) { mod2sparse_insert(r,i,mod2sparse_col(e1)); e1 = mod2sparse_next_in_row(e1); } else { mod2sparse_insert(r,i,mod2sparse_col(e2)); e2 = mod2sparse_next_in_row(e2); } } while (!mod2sparse_at_end(e1)) { mod2sparse_insert(r,i,mod2sparse_col(e1)); e1 = mod2sparse_next_in_row(e1); } while (!mod2sparse_at_end(e2)) { mod2sparse_insert(r,i,mod2sparse_col(e2)); e2 = mod2sparse_next_in_row(e2); } } }
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; }
void mod2sparse_multiply ( mod2sparse *m1, /* Left operand of multiply */ mod2sparse *m2, /* Right operand of multiply */ mod2sparse *r /* Place to store result of multiply */ ) { mod2entry *e1, *e2; int i, j, b; if (mod2sparse_cols(m1)!=mod2sparse_rows(m2) || mod2sparse_rows(m1)!=mod2sparse_rows(r) || mod2sparse_cols(m2)!=mod2sparse_cols(r)) { fprintf (stderr, "mod2sparse_multiply: Matrices have incompatible dimensions\n"); exit(1); } if (r==m1 || r==m2) { fprintf(stderr, "mod2sparse_multiply: Result matrix is the same as one of the operands\n"); exit(1); } mod2sparse_clear(r); for (i = 0; i<mod2sparse_rows(m1); i++) { if (mod2sparse_at_end(mod2sparse_first_in_row(m1,i))) { continue; } for (j = 0; j<mod2sparse_cols(m2); j++) { b = 0; e1 = mod2sparse_first_in_row(m1,i); e2 = mod2sparse_first_in_col(m2,j); while (!mod2sparse_at_end(e1) && !mod2sparse_at_end(e2)) { if (mod2sparse_col(e1)==mod2sparse_row(e2)) { b ^= 1; e1 = mod2sparse_next_in_row(e1); e2 = mod2sparse_next_in_col(e2); } else if (mod2sparse_col(e1)<mod2sparse_row(e2)) { e1 = mod2sparse_next_in_row(e1); } else { e2 = mod2sparse_next_in_col(e2); } } if (b) { mod2sparse_insert(r,i,j); } } } }