IT++ Logo
gf2mat.cpp
Go to the documentation of this file.
1 
29 #include <itpp/base/gf2mat.h>
30 #include <itpp/base/specmat.h>
31 #include <itpp/base/matfunc.h>
32 #include <itpp/base/converters.h>
33 #include <iostream>
34 
35 namespace itpp
36 {
37 
38 // ====== IMPLEMENTATION OF THE ALIST CLASS ==========
39 
41  : data_ok(false)
42 {
43  read(fname);
44 }
45 
46 void GF2mat_sparse_alist::read(const std::string &fname)
47 {
48  std::ifstream file;
49  std::string line;
50  std::stringstream ss;
51 
52  file.open(fname.c_str());
53  it_assert(file.is_open(),
54  "GF2mat_sparse_alist::read(): Could not open file \""
55  << fname << "\" for reading");
56 
57  // parse N and M:
58  getline(file, line);
59  ss << line;
60  ss >> N >> M;
61  it_assert(!ss.fail(),
62  "GF2mat_sparse_alist::read(): Wrong alist data (N or M)");
63  it_assert((N > 0) && (M > 0),
64  "GF2mat_sparse_alist::read(): Wrong alist data");
65  ss.seekg(0, std::ios::end);
66  ss.clear();
67 
68  // parse max_num_n and max_num_m
69  getline(file, line);
70  ss << line;
71  ss >> max_num_n >> max_num_m;
72  it_assert(!ss.fail(),
73  "GF2mat_sparse_alist::read(): Wrong alist data (max_num_{n,m})");
74  it_assert((max_num_n >= 0) && (max_num_n <= N) &&
75  (max_num_m >= 0) && (max_num_m <= M),
76  "GF2mat_sparse_alist::read(): Wrong alist data");
77  ss.seekg(0, std::ios::end);
78  ss.clear();
79 
80  // parse weight of each column n
81  num_nlist.set_size(N);
82  num_nlist.clear();
83  getline(file, line);
84  ss << line;
85  for (int i = 0; i < N; i++) {
86  ss >> num_nlist(i);
87  it_assert(!ss.fail(),
88  "GF2mat_sparse_alist::read(): Wrong alist data (num_nlist("
89  << i << "))");
90  it_assert((num_nlist(i) >= 0) && (num_nlist(i) <= M),
91  "GF2mat_sparse_alist::read(): Wrong alist data (num_nlist("
92  << i << "))");
93  }
94  ss.seekg(0, std::ios::end);
95  ss.clear();
96 
97  // parse weight of each row m
98  num_mlist.set_size(M);
99  num_mlist.clear();
100  getline(file, line);
101  ss << line;
102  for (int i = 0; i < M; i++) {
103  ss >> num_mlist(i);
104  it_assert(!ss.fail(),
105  "GF2mat_sparse_alist::read(): Wrong alist data (num_mlist("
106  << i << "))");
107  it_assert((num_mlist(i) >= 0) && (num_mlist(i) <= N),
108  "GF2mat_sparse_alist::read(): Wrong alist data (num_mlist("
109  << i << "))");
110  }
111  ss.seekg(0, std::ios::end);
112  ss.clear();
113 
114  // parse coordinates in the n direction with non-zero entries
115  nlist.set_size(N, max_num_n);
116  nlist.clear();
117  for (int i = 0; i < N; i++) {
118  getline(file, line);
119  ss << line;
120  for (int j = 0; j < num_nlist(i); j++) {
121  ss >> nlist(i, j);
122  it_assert(!ss.fail(),
123  "GF2mat_sparse_alist::read(): Wrong alist data (nlist("
124  << i << "," << j << "))");
125  it_assert((nlist(i, j) > 0) && (nlist(i, j) <= M),
126  "GF2mat_sparse_alist::read(): Wrong alist data (nlist("
127  << i << "," << j << "))");
128  }
129  ss.seekg(0, std::ios::end);
130  ss.clear();
131  }
132 
133  // parse coordinates in the m direction with non-zero entries
134  mlist.set_size(M, max_num_m);
135  mlist.clear();
136  for (int i = 0; i < M; i++) {
137  getline(file, line);
138  ss << line;
139  for (int j = 0; j < num_mlist(i); j++) {
140  ss >> mlist(i, j);
141  it_assert(!ss.fail(),
142  "GF2mat_sparse_alist::read(): Wrong alist data (mlist("
143  << i << "," << j << "))");
144  it_assert((mlist(i, j) > 0) && (mlist(i, j) <= N),
145  "GF2mat_sparse_alist::read(): Wrong alist data (mlist("
146  << i << "," << j << "))");
147  }
148  ss.seekg(0, std::ios::end);
149  ss.clear();
150  }
151 
152  file.close();
153  data_ok = true;
154 }
155 
156 void GF2mat_sparse_alist::write(const std::string &fname) const
157 {
159  "GF2mat_sparse_alist::write(): alist data not ready for writing");
160 
161  std::ofstream file(fname.c_str(), std::ofstream::out);
162  it_assert(file.is_open(),
163  "GF2mat_sparse_alist::write(): Could not open file \""
164  << fname << "\" for writing");
165 
166  file << N << " " << M << std::endl;
167  file << max_num_n << " " << max_num_m << std::endl;
168 
169  for (int i = 0; i < num_nlist.length() - 1; i++)
170  file << num_nlist(i) << " ";
171  file << num_nlist(num_nlist.length() - 1) << std::endl;
172 
173  for (int i = 0; i < num_mlist.length() - 1; i++)
174  file << num_mlist(i) << " ";
175  file << num_mlist(num_mlist.length() - 1) << std::endl;
176 
177  for (int i = 0; i < N; i++) {
178  for (int j = 0; j < num_nlist(i) - 1; j++)
179  file << nlist(i, j) << " ";
180  file << nlist(i, num_nlist(i) - 1) << std::endl;
181  }
182 
183  for (int i = 0; i < M; i++) {
184  for (int j = 0; j < num_mlist(i) - 1; j++)
185  file << mlist(i, j) << " ";
186  file << mlist(i, num_mlist(i) - 1) << std::endl;
187  }
188 
189  file.close();
190 }
191 
192 
194 {
195  GF2mat_sparse sbmat(M, N, max_num_m);
196 
197  for (int i = 0; i < M; i++) {
198  for (int j = 0; j < num_mlist(i); j++) {
199  sbmat.set_new(i, mlist(i, j) - 1, bin(1));
200  }
201  }
202  sbmat.compact();
203 
204  if (transpose) {
205  return sbmat.transpose();
206  }
207  else {
208  return sbmat;
209  }
210 }
211 
212 
213 // ----------------------------------------------------------------------
214 // WARNING: This method is very slow. Sparse_Mat has to be extended with
215 // some extra functions to improve the performance of this.
216 // ----------------------------------------------------------------------
218  bool transpose)
219 {
220  if (transpose) {
221  from_sparse(sbmat.transpose(), false);
222  }
223  else {
224  // check matrix dimension
225  M = sbmat.rows();
226  N = sbmat.cols();
227 
228  num_mlist.set_size(M);
229  num_nlist.set_size(N);
230 
231  // fill mlist matrix, num_mlist vector and max_num_m
232  mlist.set_size(0, 0);
233  int tmp_cols = 0; // initial number of allocated columns
234  for (int i = 0; i < M; i++) {
235  ivec temp_row(0);
236  for (int j = 0; j < N; j++) {
237  if (sbmat(i, j) == bin(1)) {
238  temp_row = concat(temp_row, j + 1);
239  }
240  }
241  int trs = temp_row.size();
242  if (trs > tmp_cols) {
243  tmp_cols = trs;
244  mlist.set_size(M, tmp_cols, true);
245  }
246  else if (trs < tmp_cols) {
247  temp_row.set_size(tmp_cols, true);
248  }
249  mlist.set_row(i, temp_row);
250  num_mlist(i) = trs;
251  }
253 
254  // fill nlist matrix, num_nlist vector and max_num_n
255  nlist.set_size(0, 0);
256  tmp_cols = 0; // initial number of allocated columns
257  for (int j = 0; j < N; j++) {
258  ivec temp_row = sbmat.get_col(j).get_nz_indices() + 1;
259  int trs = temp_row.size();
260  if (trs > tmp_cols) {
261  tmp_cols = trs;
262  nlist.set_size(N, tmp_cols, true);
263  }
264  else if (trs < tmp_cols) {
265  temp_row.set_size(tmp_cols, true);
266  }
267  nlist.set_row(j, temp_row);
268  num_nlist(j) = trs;
269  }
271 
272  data_ok = true;
273  }
274 }
275 
276 
277 // ----------------------------------------------------------------------
278 // Implementation of a dense GF2 matrix class
279 // ----------------------------------------------------------------------
280 
281 GF2mat::GF2mat(int i, int j): nrows(i), ncols(j),
282  nwords((j >> shift_divisor) + 1)
283 {
284  data.set_size(nrows, nwords);
285  data.clear();
286 }
287 
288 GF2mat::GF2mat(): nrows(1), ncols(1), nwords(1)
289 {
290  data.set_size(nrows, nwords);
291  data.clear();
292 }
293 
294 GF2mat::GF2mat(const bvec &x, bool is_column)
295 {
296  if (is_column) { // create column vector
297  nrows = length(x);
298  ncols = 1;
299  nwords = 1;
300  data.set_size(nrows, nwords);
301  data.clear();
302  for (int i = 0; i < nrows; i++) {
303  set(i, 0, x(i));
304  }
305  }
306  else { // create row vector
307  nrows = 1;
308  ncols = length(x);
309  nwords = (ncols >> shift_divisor) + 1;
310  data.set_size(nrows, nwords);
311  data.clear();
312  for (int i = 0; i < ncols; i++) {
313  set(0, i, x(i));
314  }
315  }
316 }
317 
318 
319 GF2mat::GF2mat(const bmat &X): nrows(X.rows()), ncols(X.cols())
320 {
321  nwords = (ncols >> shift_divisor) + 1;
322  data.set_size(nrows, nwords);
323  data.clear();
324  for (int i = 0; i < nrows; i++) {
325  for (int j = 0; j < ncols; j++) {
326  set(i, j, X(i, j));
327  }
328  }
329 }
330 
331 
333 {
334  nrows = X.rows();
335  ncols = X.cols();
336  nwords = (ncols >> shift_divisor) + 1;
337  data.set_size(nrows, nwords);
338  for (int i = 0; i < nrows; i++) {
339  for (int j = 0; j < nwords; j++) {
340  data(i, j) = 0;
341  }
342  }
343 
344  for (int j = 0; j < ncols; j++) {
345  for (int i = 0; i < X.get_col(j).nnz(); i++) {
346  bin b = X.get_col(j).get_nz_data(i);
347  set(X.get_col(j).get_nz_index(i), j, b);
348  }
349  }
350 }
351 
352 GF2mat::GF2mat(const GF2mat_sparse &X, int m1, int n1, int m2, int n2)
353 {
354  it_assert(X.rows() > m2, "GF2mat(): indexes out of range");
355  it_assert(X.cols() > n2, "GF2mat(): indexes out of range");
356  it_assert(m1 >= 0 && n1 >= 0 && m2 >= m1 && n2 >= n1,
357  "GF2mat::GF2mat(): indexes out of range");
358 
359  nrows = m2 - m1 + 1;
360  ncols = n2 - n1 + 1;
361  nwords = (ncols >> shift_divisor) + 1;
362  data.set_size(nrows, nwords);
363 
364  for (int i = 0; i < nrows; i++) {
365  for (int j = 0; j < nwords; j++) {
366  data(i, j) = 0;
367  }
368  }
369 
370  for (int i = 0; i < nrows; i++) {
371  for (int j = 0; j < ncols; j++) {
372  bin b = X(i + m1, j + n1);
373  set(i, j, b);
374  }
375  }
376 }
377 
378 
379 GF2mat::GF2mat(const GF2mat_sparse &X, const ivec &columns)
380 {
381  it_assert(X.cols() > max(columns),
382  "GF2mat::GF2mat(): index out of range");
383  it_assert(min(columns) >= 0,
384  "GF2mat::GF2mat(): column index must be positive");
385 
386  nrows = X.rows();
387  ncols = length(columns);
388  nwords = (ncols >> shift_divisor) + 1;
389  data.set_size(nrows, nwords);
390 
391  for (int i = 0; i < nrows; i++) {
392  for (int j = 0; j < nwords; j++) {
393  data(i, j) = 0;
394  }
395  }
396 
397  for (int j = 0; j < ncols; j++) {
398  for (int i = 0; i < X.get_col(columns(j)).nnz(); i++) {
399  bin b = X.get_col(columns(j)).get_nz_data(i);
400  set(X.get_col(columns(j)).get_nz_index(i), j, b);
401  }
402  }
403 }
404 
405 
406 void GF2mat::set_size(int m, int n, bool copy)
407 {
408  nrows = m;
409  ncols = n;
410  nwords = (ncols >> shift_divisor) + 1;
411  data.set_size(nrows, nwords, copy);
412  if (!copy)
413  data.clear();
414 }
415 
416 
418 {
419  GF2mat_sparse Z(nrows, ncols);
420  for (int i = 0; i < nrows; i++) {
421  for (int j = 0; j < ncols; j++) {
422  if (get(i, j) == 1) {
423  Z.set(i, j, 1);
424  }
425  }
426  }
427 
428  return Z;
429 }
430 
431 bvec GF2mat::bvecify() const
432 {
433  it_assert(nrows == 1 || ncols == 1,
434  "GF2mat::bvecify() matrix must be a vector");
435  int n = (nrows == 1 ? ncols : nrows);
436  bvec result(n);
437  if (nrows == 1) {
438  for (int i = 0; i < n; i++) {
439  result(i) = get(0, i);
440  }
441  }
442  else {
443  for (int i = 0; i < n; i++) {
444  result(i) = get(i, 0);
445  }
446  }
447  return result;
448 }
449 
450 
451 void GF2mat::set_row(int i, bvec x)
452 {
453  it_assert(length(x) == ncols,
454  "GF2mat::set_row(): dimension mismatch");
455  for (int j = 0; j < ncols; j++) {
456  set(i, j, x(j));
457  }
458 }
459 
460 void GF2mat::set_col(int j, bvec x)
461 {
462  it_assert(length(x) == nrows,
463  "GF2mat::set_col(): dimension mismatch");
464  for (int i = 0; i < nrows; i++) {
465  set(i, j, x(i));
466  }
467 }
468 
469 
471 {
472  GF2mat Z(m, m);
473  for (int i = 0; i < m; i++) {
474  Z.set(i, i, 1);
475  }
476  return Z;
477 }
478 
479 GF2mat GF2mat::get_submatrix(int m1, int n1, int m2, int n2) const
480 {
481  it_assert(m1 >= 0 && n1 >= 0 && m2 >= m1 && n2 >= n1
482  && m2 < nrows && n2 < ncols,
483  "GF2mat::get_submatrix() index out of range");
484  GF2mat result(m2 - m1 + 1, n2 - n1 + 1);
485 
486  for (int i = m1; i <= m2; i++) {
487  for (int j = n1; j <= n2; j++) {
488  result.set(i - m1, j - n1, get(i, j));
489  }
490  }
491 
492  return result;
493 }
494 
495 
497 {
498  it_assert(X.ncols == ncols,
499  "GF2mat::concatenate_vertical(): dimension mismatch");
500  it_assert(X.nwords == nwords,
501  "GF2mat::concatenate_vertical(): dimension mismatch");
502 
503  GF2mat result(nrows + X.nrows, ncols);
504  for (int i = 0; i < nrows; i++) {
505  for (int j = 0; j < nwords; j++) {
506  result.data(i, j) = data(i, j);
507  }
508  }
509 
510  for (int i = 0; i < X.nrows; i++) {
511  for (int j = 0; j < nwords; j++) {
512  result.data(i + nrows, j) = X.data(i, j);
513  }
514  }
515 
516  return result;
517 }
518 
520 {
521  it_assert(X.nrows == nrows,
522  "GF2mat::concatenate_horizontal(): dimension mismatch");
523 
524  GF2mat result(nrows, X.ncols + ncols);
525  for (int i = 0; i < nrows; i++) {
526  for (int j = 0; j < ncols; j++) {
527  result.set(i, j, get(i, j));
528  }
529  }
530 
531  for (int i = 0; i < nrows; i++) {
532  for (int j = 0; j < X.ncols; j++) {
533  result.set(i, j + ncols, X.get(i, j));
534  }
535  }
536 
537  return result;
538 }
539 
540 bvec GF2mat::get_row(int i) const
541 {
542  bvec result(ncols);
543  for (int j = 0; j < ncols; j++) {
544  result(j) = get(i, j);
545  }
546 
547  return result;
548 }
549 
550 bvec GF2mat::get_col(int j) const
551 {
552  bvec result(nrows);
553  for (int i = 0; i < nrows; i++) {
554  result(i) = get(i, j);
555  }
556 
557  return result;
558 }
559 
560 
561 int GF2mat::T_fact(GF2mat &T, GF2mat &U, ivec &perm) const
562 {
563  T = gf2dense_eye(nrows);
564  U = *this;
565 
566  perm = zeros_i(ncols);
567  for (int i = 0; i < ncols; i++) {
568  perm(i) = i;
569  }
570 
571  if (nrows > 250) { // avoid cluttering output ...
572  it_info_debug("Performing T-factorization of GF(2) matrix... rows: "
573  << nrows << " cols: " << ncols << " .... " << std::endl);
574  }
575  int pdone = 0;
576  for (int j = 0; j < nrows; j++) {
577  // Now working on diagonal element j,j
578  // First try find a row with a 1 in column i
579  int i1, j1;
580  for (i1 = j; i1 < nrows; i1++) {
581  for (j1 = j; j1 < ncols; j1++) {
582  if (U.get(i1, j1) == 1) { goto found; }
583  }
584  }
585 
586  return j;
587 
588  found:
589  U.swap_rows(i1, j);
590  T.swap_rows(i1, j);
591  U.swap_cols(j1, j);
592 
593  int temp = perm(j);
594  perm(j) = perm(j1);
595  perm(j1) = temp;
596 
597  // now subtract row i from remaining rows
598  for (int i1 = j + 1; i1 < nrows; i1++) {
599  if (U.get(i1, j) == 1) {
600  int ptemp = floor_i(100.0 * (i1 + j * nrows) / (nrows * nrows));
601  if (nrows > 250 && ptemp > pdone + 10) {
602  it_info_debug(ptemp << "% done.");
603  pdone = ptemp;
604  }
605  U.add_rows(i1, j);
606  T.add_rows(i1, j);
607  }
608  }
609  }
610  return nrows;
611 }
612 
613 
615  ivec &perm, int rank,
616  int r, int c) const
617 {
618  // First, update U (before re-triangulization)
619  int c0 = c;
620  for (c = 0; c < ncols; c++) {
621  if (perm(c) == c0) {
622  goto foundidx;
623  }
624  }
625  it_error("GF2mat::T_fact_update_bitflip() - internal error");
626 
627 foundidx:
628  for (int i = 0; i < nrows; i++) {
629  if (T.get(i, r) == 1) {
630  U.addto_element(i, c, 1);
631  }
632  }
633 
634  // first move column c to the end
635  bvec lastcol = U.get_col(c);
636  int temp_perm = perm(c);
637  for (int j = c; j < ncols - 1; j++) {
638  U.set_col(j, U.get_col(j + 1));
639  perm(j) = perm(j + 1);
640  }
641  U.set_col(ncols - 1, lastcol);
642  perm(ncols - 1) = temp_perm;
643 
644  // then, if the matrix is tall, also move row c to the end
645  if (nrows >= ncols) {
646  bvec lastrow_U = U.get_row(c);
647  bvec lastrow_T = T.get_row(c);
648  for (int i = c; i < nrows - 1; i++) {
649  U.set_row(i, U.get_row(i + 1));
650  T.set_row(i, T.get_row(i + 1));
651  }
652  U.set_row(nrows - 1, lastrow_U);
653  T.set_row(nrows - 1, lastrow_T);
654 
655  // Do Gaussian elimination on the last row
656  for (int j = c; j < ncols; j++) {
657  if (U.get(nrows - 1, j) == 1) {
658  U.add_rows(nrows - 1, j);
659  T.add_rows(nrows - 1, j);
660  }
661  }
662  }
663 
664  // Now, continue T-factorization from the point (rank-1,rank-1)
665  for (int j = rank - 1; j < nrows; j++) {
666  int i1, j1;
667  for (i1 = j; i1 < nrows; i1++) {
668  for (j1 = j; j1 < ncols; j1++) {
669  if (U.get(i1, j1) == 1) {
670  goto found;
671  }
672  }
673  }
674 
675  return j;
676 
677  found:
678  U.swap_rows(i1, j);
679  T.swap_rows(i1, j);
680  U.swap_cols(j1, j);
681 
682  int temp = perm(j);
683  perm(j) = perm(j1);
684  perm(j1) = temp;
685 
686  for (int i1 = j + 1; i1 < nrows; i1++) {
687  if (U.get(i1, j) == 1) {
688  U.add_rows(i1, j);
689  T.add_rows(i1, j);
690  }
691  }
692  }
693 
694  return nrows;
695 }
696 
698  ivec &perm, bvec newcol) const
699 {
700  int i0 = T.rows();
701  int j0 = U.cols();
702  it_assert(j0 > 0, "GF2mat::T_fact_update_addcol(): dimension mismatch");
703  it_assert(i0 == T.cols(),
704  "GF2mat::T_fact_update_addcol(): dimension mismatch");
705  it_assert(i0 == U.rows(),
706  "GF2mat::T_fact_update_addcol(): dimension mismatch");
707  it_assert(length(perm) == j0,
708  "GF2mat::T_fact_update_addcol(): dimension mismatch");
709  it_assert(U.get(j0 - 1, j0 - 1) == 1,
710  "GF2mat::T_fact_update_addcol(): dimension mismatch");
711  // The following test is VERY TIME-CONSUMING
712  it_assert_debug(U.row_rank() == j0,
713  "GF2mat::T_fact_update_addcol(): factorization has incorrect rank");
714 
715  bvec z = T * newcol;
716  GF2mat Utemp = U.concatenate_horizontal(GF2mat(z, 1));
717 
718  // start working on position (j0,j0)
719  int i;
720  for (i = j0; i < i0; i++) {
721  if (Utemp.get(i, j0) == 1) {
722  goto found;
723  }
724  }
725  return (false); // adding the new column would not improve the rank
726 
727 found:
728  perm.set_length(j0 + 1, true);
729  perm(j0) = j0;
730 
731  Utemp.swap_rows(i, j0);
732  T.swap_rows(i, j0);
733 
734  for (int i1 = j0 + 1; i1 < i0; i1++) {
735  if (Utemp.get(i1, j0) == 1) {
736  Utemp.add_rows(i1, j0);
737  T.add_rows(i1, j0);
738  }
739  }
740 
741  U = Utemp;
742  return (true); // the new column was successfully added
743 }
744 
745 
746 
747 
749 {
750  it_assert(nrows == ncols, "GF2mat::inverse(): Matrix must be square");
751 
752  // first compute the T-factorization
753  GF2mat T, U;
754  ivec perm;
755  int rank = T_fact(T, U, perm);
756  it_assert(rank == ncols, "GF2mat::inverse(): Matrix is not full rank");
757 
758  // backward substitution
759  for (int i = ncols - 2; i >= 0; i--) {
760  for (int j = ncols - 1; j > i; j--) {
761  if (U.get(i, j) == 1) {
762  U.add_rows(i, j);
763  T.add_rows(i, j);
764  }
765  }
766  }
767  T.permute_rows(perm, 1);
768  return T;
769 }
770 
771 int GF2mat::row_rank() const
772 {
773  GF2mat T, U;
774  ivec perm;
775  int rank = T_fact(T, U, perm);
776  return rank;
777 }
778 
779 bool GF2mat::is_zero() const
780 {
781  for (int i = 0; i < nrows; i++) {
782  for (int j = 0; j < nwords; j++) {
783  if (data(i, j) != 0) {
784  return false;
785  }
786  }
787  }
788  return true;
789 }
790 
791 bool GF2mat::operator==(const GF2mat &X) const
792 {
793  if (X.nrows != nrows) { return false; }
794  if (X.ncols != ncols) { return false; }
795  it_assert(X.nwords == nwords, "GF2mat::operator==() dimension mismatch");
796 
797  for (int i = 0; i < nrows; i++) {
798  for (int j = 0; j < nwords; j++) {
799  // if (X.get(i,j)!=get(i,j)) {
800  if (X.data(i, j) != data(i, j)) {
801  return false;
802  }
803  }
804  }
805  return true;
806 }
807 
808 
809 void GF2mat::add_rows(int i, int j)
810 {
811  it_assert(i >= 0 && i < nrows, "GF2mat::add_rows(): out of range");
812  it_assert(j >= 0 && j < nrows, "GF2mat::add_rows(): out of range");
813  for (int k = 0; k < nwords; k++) {
814  data(i, k) ^= data(j, k);
815  }
816 }
817 
818 void GF2mat::swap_rows(int i, int j)
819 {
820  it_assert(i >= 0 && i < nrows, "GF2mat::swap_rows(): index out of range");
821  it_assert(j >= 0 && j < nrows, "GF2mat::swap_rows(): index out of range");
822  for (int k = 0; k < nwords; k++) {
823  unsigned char temp = data(i, k);
824  data(i, k) = data(j, k);
825  data(j, k) = temp;
826  }
827 }
828 
829 void GF2mat::swap_cols(int i, int j)
830 {
831  it_assert(i >= 0 && i < ncols, "GF2mat::swap_cols(): index out of range");
832  it_assert(j >= 0 && j < ncols, "GF2mat::swap_cols(): index out of range");
833  bvec temp = get_col(i);
834  set_col(i, get_col(j));
835  set_col(j, temp);
836 }
837 
838 
839 void GF2mat::operator=(const GF2mat &X)
840 {
841  nrows = X.nrows;
842  ncols = X.ncols;
843  nwords = X.nwords;
844  data = X.data;
845 }
846 
847 GF2mat operator*(const GF2mat &X, const GF2mat &Y)
848 {
849  it_assert(X.ncols == Y.nrows, "GF2mat::operator*(): dimension mismatch");
850  it_assert(X.nwords > 0, "Gfmat::operator*(): dimension mismatch");
851  it_assert(Y.nwords > 0, "Gfmat::operator*(): dimension mismatch");
852 
853  /*
854  // this can be done more efficiently?
855  GF2mat result(X.nrows,Y.ncols);
856  for (int i=0; i<X.nrows; i++) {
857  for (int j=0; j<Y.ncols; j++) {
858  bin b=0;
859  for (int k=0; k<X.ncols; k++) {
860  bin x = X.get(i,k);
861  bin y = Y.get(k,j);
862  b ^= (x&y);
863  }
864  result.set(i,j,b);
865  }
866  }
867  return result; */
868 
869  // is this better?
870  return mult_trans(X, Y.transpose());
871 }
872 
873 bvec operator*(const GF2mat &X, const bvec &y)
874 {
875  it_assert(length(y) == X.ncols, "GF2mat::operator*(): dimension mismatch");
876  it_assert(X.nwords > 0, "Gfmat::operator*(): dimension mismatch");
877 
878  /*
879  // this can be done more efficiently?
880  bvec result = zeros_b(X.nrows);
881  for (int i=0; i<X.nrows; i++) {
882  // do the nwords-1 data columns first
883  for (int j=0; j<X.nwords-1; j++) {
884  int ind = j<<shift_divisor;
885  unsigned char r=X.data(i,j);
886  while (r) {
887  result(i) ^= (r & y(ind));
888  r >>= 1;
889  ind++;
890  }
891  }
892  // do the last column separately
893  for (int j=(X.nwords-1)<<shift_divisor; j<X.ncols; j++) {
894  result(i) ^= (X.get(i,j) & y(j));
895  }
896  }
897  return result; */
898 
899  // is this better?
900  return (mult_trans(X, GF2mat(y, 0))).bvecify();
901 }
902 
903 GF2mat mult_trans(const GF2mat &X, const GF2mat &Y)
904 {
905  it_assert(X.ncols == Y.ncols, "GF2mat::mult_trans(): dimension mismatch");
906  it_assert(X.nwords > 0, "GF2mat::mult_trans(): dimension mismatch");
907  it_assert(Y.nwords > 0, "GF2mat::mult_trans(): dimension mismatch");
908  it_assert(X.nwords == Y.nwords, "GF2mat::mult_trans(): dimension mismatch");
909 
910  GF2mat result(X.nrows, Y.nrows);
911 
912  for (int i = 0; i < X.nrows; i++) {
913  for (int j = 0; j < Y.nrows; j++) {
914  bin b = 0;
915  int kindx = i;
916  int kindy = j;
917  for (int k = 0; k < X.nwords; k++) {
918  unsigned char r = X.data(kindx) & Y.data(kindy);
919  /* The following can be speeded up by using a small lookup
920  table for the number of ones and shift only a few times (or
921  not at all if table is large) */
922  while (r) {
923  b ^= r & 1;
924  r >>= 1;
925  };
926  kindx += X.nrows;
927  kindy += Y.nrows;
928  }
929  result.set(i, j, b);
930  }
931  }
932  return result;
933 }
934 
936 {
937  // CAN BE SPEEDED UP
938  GF2mat result(ncols, nrows);
939 
940  for (int i = 0; i < nrows; i++) {
941  for (int j = 0; j < ncols; j++) {
942  result.set(j, i, get(i, j));
943  }
944  }
945  return result;
946 }
947 
948 GF2mat operator+(const GF2mat &X, const GF2mat &Y)
949 {
950  it_assert(X.nrows == Y.nrows, "GF2mat::operator+(): dimension mismatch");
951  it_assert(X.ncols == Y.ncols, "GF2mat::operator+(): dimension mismatch");
952  it_assert(X.nwords == Y.nwords, "GF2mat::operator+(): dimension mismatch");
953  GF2mat result(X.nrows, X.ncols);
954 
955  for (int i = 0; i < X.nrows; i++) {
956  for (int j = 0; j < X.nwords; j++) {
957  result.data(i, j) = X.data(i, j) ^ Y.data(i, j);
958  }
959  }
960 
961  return result;
962 }
963 
964 void GF2mat::permute_cols(ivec &perm, bool I)
965 {
966  it_assert(length(perm) == ncols,
967  "GF2mat::permute_cols(): dimensions do not match");
968 
969  GF2mat temp = (*this);
970  for (int j = 0; j < ncols; j++) {
971  if (I == 0) {
972  set_col(j, temp.get_col(perm(j)));
973  }
974  else {
975  set_col(perm(j), temp.get_col(j));
976  }
977  }
978 }
979 
980 void GF2mat::permute_rows(ivec &perm, bool I)
981 {
982  it_assert(length(perm) == nrows,
983  "GF2mat::permute_rows(): dimensions do not match");
984 
985  GF2mat temp = (*this);
986  for (int i = 0; i < nrows; i++) {
987  if (I == 0) {
988  for (int j = 0; j < nwords; j++) {
989  data(i, j) = temp.data(perm(i), j);
990  }
991  }
992  else {
993  for (int j = 0; j < nwords; j++) {
994  data(perm(i), j) = temp.data(i, j);
995  }
996  }
997  }
998 }
999 
1000 
1001 std::ostream &operator<<(std::ostream &os, const GF2mat &X)
1002 {
1003  int i, j;
1004  os << "---- GF(2) matrix of dimension " << X.nrows << "*" << X.ncols
1005  << " -- Density: " << X.density() << " ----" << std::endl;
1006 
1007  for (i = 0; i < X.nrows; i++) {
1008  os << " ";
1009  for (j = 0; j < X.ncols; j++) {
1010  os << X.get(i, j) << " ";
1011  }
1012  os << std::endl;
1013  }
1014 
1015  return os;
1016 }
1017 
1018 double GF2mat::density() const
1019 {
1020  int no_of_ones = 0;
1021 
1022  for (int i = 0; i < nrows; i++) {
1023  for (int j = 0; j < ncols; j++) {
1024  no_of_ones += (get(i, j) == 1 ? 1 : 0);
1025  }
1026  }
1027 
1028  return ((double) no_of_ones) / (nrows*ncols);
1029 }
1030 
1031 
1033 {
1034  // 3 64-bit unsigned words for: nrows, ncols and nwords + rest for char data
1035  uint64_t bytecount = 3 * sizeof(uint64_t)
1036  + X.nrows * X.nwords * sizeof(char);
1037  f.write_data_header("GF2mat", bytecount);
1038 
1039  f.low_level_write(static_cast<uint64_t>(X.nrows));
1040  f.low_level_write(static_cast<uint64_t>(X.ncols));
1041  f.low_level_write(static_cast<uint64_t>(X.nwords));
1042  for (int i = 0; i < X.nrows; i++) {
1043  for (int j = 0; j < X.nwords; j++) {
1044  f.low_level_write(static_cast<char>(X.data(i, j)));
1045  }
1046  }
1047  return f;
1048 }
1049 
1051 {
1053 
1054  f.read_data_header(h);
1055  if (h.type == "GF2mat") {
1056  uint64_t tmp;
1057  f.low_level_read(tmp);
1058  X.nrows = static_cast<int>(tmp);
1059  f.low_level_read(tmp);
1060  X.ncols = static_cast<int>(tmp);
1061  f.low_level_read(tmp);
1062  X.nwords = static_cast<int>(tmp);
1063  X.data.set_size(X.nrows, X.nwords);
1064  for (int i = 0; i < X.nrows; i++) {
1065  for (int j = 0; j < X.nwords; j++) {
1066  char r;
1067  f.low_level_read(r);
1068  X.data(i, j) = static_cast<unsigned char>(r);
1069  }
1070  }
1071  }
1072  else {
1073  it_error("it_ifile &operator>>() - internal error");
1074  }
1075 
1076  return f;
1077 }
1078 
1079 } // namespace itpp
1080 
SourceForge Logo

Generated on Sat May 25 2013 16:32:18 for IT++ by Doxygen 1.8.2