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_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_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_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_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); } } }
void mod2sparse_clear ( mod2sparse *r ) { mod2block *b; mod2entry *e; int i, j; for (i = 0; i<mod2sparse_rows(r); i++) { e = &r->rows[i]; #ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE e->left = e->right = e->up = e->down = e; #else e->left = e->right = e->down = e; #endif } for (j = 0; j<mod2sparse_cols(r); j++) { e = &r->cols[j]; #ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE e->left = e->right = e->up = e->down = e; #else e->left = e->right = e->down = e; #endif } while (r->blocks!=0) { b = r->blocks; r->blocks = b->next; free(b); } }
void read_pchk ( char *pchk_file ) { FILE *f; f = open_file_std(pchk_file,"rb"); if (f==NULL) { fprintf(stderr,"Can't open parity check file: %s\n",pchk_file); exit(1); } if (intio_read(f)!=('P'<<8)+0x80) { fprintf(stderr,"File %s doesn't contain a parity check matrix\n",pchk_file); exit(1); } H = mod2sparse_read(f); if (H==0) { fprintf(stderr,"Error reading parity check matrix from %s\n",pchk_file); exit(1); } M = mod2sparse_rows(H); N = mod2sparse_cols(H); fclose(f); }
void mod2sparse_clear ( mod2sparse *r ) { mod2block *b; mod2entry *e; int i, j; for (i = 0; i<mod2sparse_rows(r); i++) { e = &r->rows[i]; #ifndef OPTIMIZEFORMEMORY e->left = e->right = e->up = e->down = e; #else e->left = e->right = e->down = e; #endif } for (j = 0; j<mod2sparse_cols(r); j++) { e = &r->cols[j]; #ifndef OPTIMIZEFORMEMORY e->left = e->right = e->up = e->down = e; #else e->left = e->right = e->down = e; #endif } while (r->blocks!=0) { b = r->blocks; r->blocks = b->next; free(b); } }
double expected_parity_errors ( mod2sparse *H, /* Parity check matrix */ double *bpr /* Bit probabilities */ ) { mod2entry *f; double ee, p; int M, i, j; M = mod2sparse_rows(H); ee = 0; for (i = 0; i<M; i++) { p = 0; for (f = mod2sparse_first_in_row(H,i); !mod2sparse_at_end(f); f = mod2sparse_next_in_row(f)) { j = mod2sparse_col(f); p = p * (1-bpr[j]) + (1-p) * bpr[j]; } ee += p; } return ee; }
void mod2sparse_mulvec ( mod2sparse *m, /* The sparse matrix, with M rows and N columns */ char *u, /* The input vector, N long */ char *v /* Place to store the result, M long */ ) { mod2entry *e; int M, N; int i, j; M = mod2sparse_rows(m); N = mod2sparse_cols(m); for (i = 0; i<M; i++) v[i] = 0; for (j = 0; j<N; j++) { if (u[j]) { for (e = mod2sparse_first_in_col(m,j); !mod2sparse_at_end(e); e = mod2sparse_next_in_col(e)) { v[mod2sparse_row(e)] ^= 1; } } } }
mod2entry *mod2sparse_find ( mod2sparse *m, int row, int col ) { mod2entry *re, *ce; if (row<0 || row>=mod2sparse_rows(m) || col<0 || col>=mod2sparse_cols(m)) { fprintf(stderr,"mod2sparse_find: row or column index out of bounds\n"); exit(1); } /* Check last entries in row. */ re = mod2sparse_last_in_row(m,row); if (mod2sparse_at_end(re) || mod2sparse_col(re)<col) { return 0; } if (mod2sparse_col(re)==col) { return re; } #ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE ce = mod2sparse_last_in_col(m,col); if (mod2sparse_at_end(ce) || mod2sparse_row(ce)<row) { return 0; } if (mod2sparse_row(ce)==row) { return ce; } #endif /* Search row and column in parallel, from the front. */ re = mod2sparse_first_in_row(m,row); ce = mod2sparse_first_in_col(m,col); for (;;) { if (mod2sparse_at_end(re) || mod2sparse_col(re)>col) { return 0; } if (mod2sparse_col(re)==col) { return re; } if (mod2sparse_at_end(ce) || mod2sparse_row(ce)>row) { return 0; } if (mod2sparse_row(ce)==row) { return ce; } re = mod2sparse_next_in_row(re); ce = mod2sparse_next_in_col(ce); } }
void mod2sparse_add_col ( mod2sparse *m1, /* Matrix containing column to add to */ int col1, /* Index in this matrix of column to add to */ mod2sparse *m2, /* Matrix containing column to add from */ int col2 /* Index in this matrix of column to add from */ ) { mod2entry *f1, *f2, *ft; if (mod2sparse_rows(m1)<mod2sparse_rows(m2)) { fprintf (stderr, "mod2sparse_add_col: Column added to is shorter than column added from\n"); exit(1); } if (col1<0 || col1>=mod2sparse_cols(m1) || col2<0 || col2>=mod2sparse_cols(m2)) { fprintf (stderr,"mod2sparse_add_col: Column index out of range\n"); exit(1); } f1 = mod2sparse_first_in_col(m1,col1); f2 = mod2sparse_first_in_col(m2,col2); while (!mod2sparse_at_end(f1) && !mod2sparse_at_end(f2)) { if (mod2sparse_row(f1)>mod2sparse_row(f2)) { mod2sparse_insert(m1,mod2sparse_row(f2),col1); f2 = mod2sparse_next_in_col(f2); } else { ft = mod2sparse_next_in_col(f1); if (mod2sparse_row(f1)==mod2sparse_row(f2)) { mod2sparse_delete(m1,f1); f2 = mod2sparse_next_in_col(f2); } f1 = ft; } } while (!mod2sparse_at_end(f2)) { mod2sparse_insert(m1,mod2sparse_row(f2),col1); f2 = mod2sparse_next_in_col(f2); } }
void mod2sparse_add_row ( mod2sparse *m1, /* Matrix containing row to add to */ int row1, /* Index in this matrix of row to add to */ mod2sparse *m2, /* Matrix containing row to add from */ int row2 /* Index in this matrix of row to add from */ ) { mod2entry *f1, *f2, *ft; if (mod2sparse_cols(m1)<mod2sparse_cols(m2)) { fprintf (stderr, "mod2sparse_add_row: row added to is shorter than row added from\n"); exit(1); } if (row1<0 || row1>=mod2sparse_rows(m1) || row2<0 || row2>=mod2sparse_rows(m2)) { fprintf (stderr,"mod2sparse_add_row: row index out of range\n"); exit(1); } f1 = mod2sparse_first_in_row(m1,row1); f2 = mod2sparse_first_in_row(m2,row2); while (!mod2sparse_at_end(f1) && !mod2sparse_at_end(f2)) { if (mod2sparse_col(f1)>mod2sparse_col(f2)) { mod2sparse_insert(m1,row1,mod2sparse_col(f2)); f2 = mod2sparse_next_in_row(f2); } else { ft = mod2sparse_next_in_row(f1); if (mod2sparse_col(f1)==mod2sparse_col(f2)) { mod2sparse_delete(m1,f1); f2 = mod2sparse_next_in_row(f2); } f1 = ft; } } while (!mod2sparse_at_end(f2)) { mod2sparse_insert(m1,row1,mod2sparse_col(f2)); f2 = mod2sparse_next_in_row(f2); } }
int mod2sparse_equal ( mod2sparse *m1, mod2sparse *m2 ) { mod2entry *e1, *e2; int i; if (mod2sparse_rows(m1)!=mod2sparse_rows(m2) || mod2sparse_cols(m1)!=mod2sparse_cols(m2)) { fprintf(stderr,"mod2sparse_equal: Matrices have different dimensions\n"); exit(1); } for (i = 0; i<mod2sparse_rows(m1); 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)) { return 0; } e1 = mod2sparse_next_in_row(e1); e2 = mod2sparse_next_in_row(e2); } if (!mod2sparse_at_end(e1) || !mod2sparse_at_end(e2)) { return 0; } } return 1; }
int check ( mod2sparse *H, /* Parity check matrix */ char *dblk, /* Guess for codeword */ char *pchk /* Place to store parity checks */ ) { int M, i, c; M = mod2sparse_rows(H); mod2sparse_mulvec (H, dblk, pchk); c = 0; for (i = 0; i<M; i++) { c += pchk[i]; } return c; }
int mod2sparse_write ( FILE *f, mod2sparse *m ) { mod2entry *e; int i; intio_write(f,m->n_rows); if (ferror(f)) return 0; intio_write(f,m->n_cols); if (ferror(f)) return 0; for (i = 0; i<mod2sparse_rows(m); i++) { e = mod2sparse_first_in_row(m,i); if (!mod2sparse_at_end(e)) { intio_write (f, -(i+1)); if (ferror(f)) return 0; while (!mod2sparse_at_end(e)) { intio_write (f, mod2sparse_col(e)+1); if (ferror(f)) return 0; e = mod2sparse_next_in_row(e); } } } intio_write(f,0); if (ferror(f)) return 0; return 1; }
int mod2sparse_count_row ( mod2sparse *m, int row ) { mod2entry *e; int count; if (row<0 || row>=mod2sparse_rows(m)) { fprintf(stderr,"mod2sparse_count_row: row index out of bounds\n"); exit(1); } count = 0; for (e = mod2sparse_first_in_row(m,row); !mod2sparse_at_end(e); e = mod2sparse_next_in_row(e)) { count += 1; } return count; }
void mod2sparse_clear ( mod2sparse *r ) { mod2block *b; mod2entry *e; int i, j; for (i = 0; i<mod2sparse_rows(r); i++) { e = &r->rows[i]; e->left = e->right = e->up = e->down = e; } for (j = 0; j<mod2sparse_cols(r); j++) { e = &r->cols[j]; e->left = e->right = e->up = e->down = e; } while (r->blocks!=0) { b = r->blocks; r->blocks = b->next; free(b); } }
void mod2sparse_print ( FILE *f, mod2sparse *m ) { int rdigits, cdigits; mod2entry *e; int i; rdigits = mod2sparse_rows(m)<=10 ? 1 : mod2sparse_rows(m)<=100 ? 2 : mod2sparse_rows(m)<=1000 ? 3 : mod2sparse_rows(m)<=10000 ? 4 : mod2sparse_rows(m)<=100000 ? 5 : 6; cdigits = mod2sparse_cols(m)<=10 ? 1 : mod2sparse_cols(m)<=100 ? 2 : mod2sparse_cols(m)<=1000 ? 3 : mod2sparse_cols(m)<=10000 ? 4 : mod2sparse_cols(m)<=100000 ? 5 : 6; for (i = 0; i<mod2sparse_rows(m); i++) { fprintf(f,"%*d:",rdigits,i); e = mod2sparse_first_in_row(m,i); while (!mod2sparse_at_end(e)) { fprintf(f," %*d",cdigits,mod2sparse_col(e)); e = mod2sparse_next_in_row(e); } fprintf(f,"\n"); } }
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); } } } }
void read_gen ( char *gen_file, /* Name of generator matrix file */ int cols_only, /* Read only column ordering? */ int no_pchk_file /* No parity check file used? */ ) { int M2, N2; FILE *f; int i; f = open_file_std(gen_file,"rb"); if (f==NULL) { fprintf(stderr,"Can't open generator matrix file: %s\n",gen_file); exit(1); } if (intio_read(f)!=('G'<<8)+0x80) { fprintf(stderr,"File %s doesn't contain a generator matrix\n",gen_file); exit(1); } if (fread (&type, 1, 1, f) != 1) goto error; M2 = intio_read(f); N2 = intio_read(f); if (feof(f) || ferror(f)) goto error; if (no_pchk_file) { M = M2; N = N2; } else { if (M2!=M || N2!=N) { fprintf(stderr, "Generator matrix and parity-check matrix are incompatible\n"); exit(1); } } cols = chk_alloc (N, sizeof *cols); rows = chk_alloc (M, sizeof *rows); for (i = 0; i<N; i++) { cols[i] = intio_read(f); if (feof(f) || ferror(f)) goto error; } if (!cols_only) { switch (type) { case 's': { for (i = 0; i<M; i++) { rows[i] = intio_read(f); if (feof(f) || ferror(f)) goto error; } if ((L = mod2sparse_read(f)) == 0) goto error; if ((U = mod2sparse_read(f)) == 0) goto error; if (mod2sparse_rows(L)!=M || mod2sparse_cols(L)!=M) goto garbled; if (mod2sparse_rows(U)!=M || mod2sparse_cols(U)<M) goto garbled; break; } case 'd': { if ((G = mod2dense_read(f)) == 0) goto error; if (mod2dense_rows(G)!=M || mod2dense_cols(G)!=N-M) goto garbled; break; } case 'm': { if ((G = mod2dense_read(f)) == 0) goto error; if (mod2dense_rows(G)!=M || mod2dense_cols(G)!=M) goto garbled; break; } default: { fprintf(stderr, "Unknown type of generator matrix in file %s\n",gen_file); exit(1); } } } fclose(f); return; error: fprintf(stderr,"Error reading generator matrix from file %s\n",gen_file); exit(1); garbled: fprintf(stderr,"Garbled generator matrix in file %s\n",gen_file); exit(1); }
int mod2sparse_backward_sub ( mod2sparse *U, /* Matrix that is upper triangular after reordering */ int *cols, /* Array of indexes (from 0) of columns for new order */ char *y, /* Vector on right of equation */ char *z /* Place to store solution, also reordered */ ) { int K, i, j, ii, b, d; mod2entry *e; K = mod2sparse_rows(U); /* Make sure that U is upper-triangular, after column re-ordering. */ for (i = 0; i<K; i++) { ii = cols ? cols[i] : i; e = mod2sparse_last_in_col(U,ii); if (!mod2sparse_at_end(e) && mod2sparse_row(e)>i) { fprintf(stderr, "mod2sparse_backward_sub: Matrix is not upper-triangular\n"); exit(1); } } /* Solve system by backward substitution. */ for (i = K-1; i>=0; i--) { ii = cols ? cols[i] : i; /* Look at bits in this row, forming inner product with partial solution, and seeing if the diagonal is 1. */ d = 0; b = 0; for (e = mod2sparse_first_in_row(U,i); !mod2sparse_at_end(e); e = mod2sparse_next_in_row(e)) { j = mod2sparse_col(e); if (j==ii) { d = 1; } else { b ^= z[j]; } } /* Check for no solution if the diagonal isn't 1. */ if (!d && b!=y[i]) { return 0; } /* Set bit of solution, zero if arbitrary. */ z[ii] = b^y[i]; } return 1; }
mod2entry *mod2sparse_insert ( mod2sparse *m, int row, int col ) { #ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE mod2entry *re, *ce, *ne; #else mod2entry *re, *ce, *ne, *ce2; #endif if (row<0 || row>=mod2sparse_rows(m) || col<0 || col>=mod2sparse_cols(m)) { fprintf(stderr,"mod2sparse_insert: row or column index out of bounds\n"); exit(1); } /* Find old entry and return it, or allocate new entry and insert into row. */ re = mod2sparse_last_in_row(m,row); if (!mod2sparse_at_end(re) && mod2sparse_col(re)==col) { return re; } if (mod2sparse_at_end(re) || mod2sparse_col(re)<col) { re = re->right; } else { re = mod2sparse_first_in_row(m,row); for (;;) { if (!mod2sparse_at_end(re) && mod2sparse_col(re)==col) { return re; } if (mod2sparse_at_end(re) || mod2sparse_col(re)>col) { break; } re = mod2sparse_next_in_row(re); } } ne = alloc_entry(m); ne->row = row; ne->col = col; ne->left = re->left; ne->right = re; ne->left->right = ne; ne->right->left = ne; /* Insert new entry into column. */ #ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE /* If we find an existing entry here, the matrix must be garbled, since we didn't find it in the row. */ ce = mod2sparse_last_in_col(m,col); if (!mod2sparse_at_end(ce) && mod2sparse_row(ce)==row) { fprintf(stderr,"mod2sparse_insert: Garbled matrix\n"); exit(1); } if (mod2sparse_at_end(ce) || mod2sparse_row(ce)<row) { ce = ce->down; } else { #else ce2 = &(m->cols[col]); #endif ce = mod2sparse_first_in_col(m,col); for (;;) { if (!mod2sparse_at_end(ce) && mod2sparse_row(ce)==row) { fprintf(stderr,"mod2sparse_insert: Garbled matrix\n"); exit(1); } if (mod2sparse_at_end(ce) || mod2sparse_row(ce)>row) { break; } #ifdef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE ce2 = ce; #endif ce = mod2sparse_next_in_col(ce); } #ifndef SPARSE_MATRIX_OPT_FOR_LDPC_STAIRCASE } ne->up = ce->up; ne->down = ce; ne->up->down = ne; ne->down->up = ne; #else ne->down = ce; ce2->down = ne; #endif /* Return the new entry. */ return ne; }
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; }