File: gf2mat.h

package info (click to toggle)
libitpp 4.0.4-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 7,520 kB
  • ctags: 6,341
  • sloc: cpp: 51,608; sh: 9,248; makefile: 636; fortran: 8
file content (500 lines) | stat: -rw-r--r-- 16,736 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
/*!
 * \file
 * \brief Definition of a class for algebra on GF(2) (binary) matrices
 * \author Erik G. Larsson and Adam Piatyszek
 *
 * -------------------------------------------------------------------------
 *
 * IT++ - C++ library of mathematical, signal processing, speech processing,
 *        and communications classes and functions
 *
 * Copyright (C) 1995-2008  (see AUTHORS file for a list of contributors)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * -------------------------------------------------------------------------
 *
 * Two representations are offered: GF2mat_sparse for sparse GF(2)
 * matrices and GF2mat for dense GF(2) matrices. Conversions between
 * dense and sparse GF(2) are also possible.
 *
 * Binary vectors are represented either via the bvec class (memory
 * typically is not an issue here) or as n*1 (or 1*n) GF(2) matrix.
 *
 * Note that the \c bmat class also provides some functionality for
 * matrix algebra over GF(2) but this class is based on \c Mat<> which
 * has a fundamentally different addressing mechanism and which is
 * much less memory efficient (\c Mat<> uses one byte memory minimum
 * per element).
 */

#ifndef GF2MAT_H
#define GF2MAT_H

#include <itpp/base/vec.h>
#include <itpp/base/mat.h>
#include <itpp/base/svec.h>
#include <itpp/base/smat.h>
#include <itpp/base/itfile.h>


namespace itpp {

  // ----------------------------------------------------------------------
  // Sparse GF(2) matrix class
  // ----------------------------------------------------------------------

  //! Sparse GF(2) vector
  typedef Sparse_Vec<bin> GF2vec_sparse;

  //! Sparse GF(2) matrix
  typedef Sparse_Mat<bin> GF2mat_sparse;


  // ----------------------------------------------------------------------
  // Alist parameterization of sparse GF(2) matrix class
  // ----------------------------------------------------------------------

  /*!
    \relatesalso GF2mat_sparse
    \brief Parameterized "alist" representation of sparse GF(2) matrix
    \author Adam Piatyszek and Erik G. Larsson

    This class is used to provide a parameterized representation of a \c
    GF2mat_sparse class. The format is compatible with the "alist" format
    defined by David MacKay, Matthew Davey and John Lafferty:
    - http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html

    For examples of "alist" representation visit David MacKay's Encyclopedia
    of Sparse Graph Codes:
    - http://www.inference.phy.cam.ac.uk/mackay/codes/data.html
  */
  class GF2mat_sparse_alist {
  public:
    //! Default constructor
    GF2mat_sparse_alist() : data_ok(false) {}
    //! Constructor, which reads alist data from a file named \c fname
    GF2mat_sparse_alist(const std::string &fname);

    //! Read alist data from a file named \c fname
    void read(const std::string &fname);
    //! Write alist data to a file named \c fname
    void write(const std::string &fname) const;

    /*!
      \brief Convert "alist" representation to \c GF2mat_sparse

      \param transpose Indicates whether a matrix should be transposed
      during the conversion process
    */
    GF2mat_sparse to_sparse(bool transpose = false) const;

    /*!
      \brief Import "alist" representation from \c GF2mat_sparse

      \param mat Matrix to import
      \param transpose Indicates whether a matrix should be transposed
      during the conversion process
    */
    void from_sparse(const GF2mat_sparse &mat, bool transpose = false);

  protected:
    //! Flag indicating that "alist" matrix data are properly set
    bool data_ok;
    //! Size of the matrix: \c M rows x \c N columns
    int M;
    //! Size of the matrix: \c M rows x \c N columns
    int N;
    //! List of integer coordinates in the m direction with non-zero entries
    imat mlist;
    //! List of integer coordinates in the n direction with non-zero entries
    imat nlist;
    //! Weight of each row m
    ivec num_mlist;
    //! Weight of each column n
    ivec num_nlist;
    //! Maximum weight of rows
    int max_num_m;
    //! Maximum weight of columns
    int max_num_n;
  };


  // ----------------------------------------------------------------------
  // Dense GF(2) matrix class
  // ----------------------------------------------------------------------

  /*!
    \relatesalso bmat
    \brief Class for dense GF(2) matrices
    \author Erik G. Larsson

    This class can be used as an alternative to \c bmat to represent
    GF(2) matrices. It extends the functionality of \c bmat in two ways:

    - \c GF2mat makes more efficient use of computer memory than \c bmat
    (one bit in the matrix requires one bit of memory)
    - \c GF2mat provides several functions for linear algebra and matrix
    factorizations

    See also \c GF2mat_sparse which offers an efficient representation
    of sparse GF(2) matrices, and \c GF2mat_sparse_alist for a
    parameterized representation of sparse GF(2) matrices.
  */
  class GF2mat {
  public:

    // ----------- Constructors -----------

    //! Default constructor (gives an empty 1 x 1 matrix)
    GF2mat();

    //! Construct an empty (all-zero) m x n matrix
    GF2mat(int m, int n);

    //! Construct a dense GF(2) matrix from a sparse GF(2) matrix
    GF2mat(const GF2mat_sparse &X);

    /*! \brief Constructor, from subset of sparse GF(2) matrix

    This constructor forms a dense GF(2) matrix from a subset (m1,n1)
    to (m2,n2) of a sparse GF(2) matrix */
    GF2mat(const GF2mat_sparse &X, int m1, int n1, int m2, int n2);

    /*! \brief Constructor, from subset of sparse GF(2) matrix

    This constructor forms a dense GF(2) matrix from a subset of
    columns in sparse GF(2) matrix

    \param X matrix to copy from
    \param columns subset of columns to copy
    */
    GF2mat(const GF2mat_sparse &X, const ivec &columns);

    /*!
      \brief Create a dense GF(2) matrix from a single vector.

      \param x The input vector
      \param is_column A parameter that indicates whether the result should
      be a row vector (false), or a column vector (true - default)
    */
    GF2mat(const bvec &x, bool is_column = true);

    //! Create a dense GF(2) matrix from a bmat
    GF2mat(const bmat &X);

    //! Set size of GF(2) matrix. If copy = true, keep data before resizing.
    void set_size(int m, int n, bool copy = false);

    //! Create a sparse GF(2) matrix from a dense GF(2) matrix
    GF2mat_sparse sparsify() const;

    //! Create a bvec from a GF(2) matrix (must have one column or one row)
    bvec bvecify() const;

    // ----------- Elementwise manipulation and simple functions -------------

    //! Getting element
    inline bin get(int i, int j) const;

    //! Getting element
    inline bin operator()(int i, int j) const { return get(i,j); };

    //! Set element i,j to s (0 or 1)
    inline void set(int i, int j, bin s);

    //! Add s (0 or 1) to element (i,j)
    inline void addto_element(int i, int j, bin s);

    //! Set column j to a binary vector x
    void set_col(int j, bvec x);

    //! Set row i to a binary vector x
    void set_row(int i, bvec x);

    //! Check whether the matrix is identical to zero
    bool is_zero() const;

    //! Swap rows i and j
    void swap_rows(int i, int j);

    //! Swap columns i and j
    void swap_cols(int i, int j);

    /*! \brief Multiply from left with permutation matrix (permute rows).

    \param perm Permutation vector
    \param I Parameter that determines permutation.
    I=0: apply permutation, I=1: apply inverse permutation
    */
    void permute_rows(ivec &perm, bool I);

    /*! \brief Multiply a matrix from right with a permutation matrix
      (i.e., permute the columns).

    \param perm Permutation vector
    \param I Parameter that determines permutation.
    I=0: apply permutation, I=1: apply inverse permutation
    */
    void permute_cols(ivec &perm, bool I);

    //! Transpose
    GF2mat transpose() const;

    //! Submatrix from (m1,n1) to (m2,n2)
    GF2mat get_submatrix(int m1, int n1, int m2, int n2) const;

    //! Concatenate horizontally (append X on the right side of matrix)
    GF2mat concatenate_horizontal(const GF2mat &X) const;

    //! Concatenate vertically (append X underneath)
    GF2mat concatenate_vertical(const GF2mat &X) const;

    //! Get row
    bvec get_row(int i) const;

    //! Get column
    bvec get_col(int j) const;

    //! Compute the matrix density (fraction of elements equal to "1")
    double density() const;

    //! Get number of rows
    int rows() const { return nrows; }

    //! Get number of columns
    int cols() const { return ncols; }

    /*! \brief Add (or equivalently, subtract) rows

    This function updates row i according to row_i = row_i+row_j

    \param i Row to add to. This row will be modified
    \param j Row to add. This row will <b>not</b> be modified.
    */
    void add_rows(int i, int j);

    // ---------- Linear algebra --------------

    /*!  \brief Inversion.

    The matrix must be invertible, otherwise the
      function will terminate with an error.
    */
    GF2mat inverse() const;

    //! Returns the number of linearly independent rows
    int row_rank() const;

    /*! \brief TXP factorization.

    Given X, compute a factorization of the form U=TXP, where U is
      upper triangular, T is square and invertible, and P is a
      permutation matrix.  This is basically an "LU"-factorization,
      but not called so here because T is not necessarily lower
      triangular.  The matrix X may have any dimension. The
      permutation matrix P is represented as a permutation vector.

      The function returns the row rank of X.  (If X is full row rank,
      then the number of rows is returned.)

      The function uses Gaussian elimination combined with
      permutations.  The computational complexity is O(m*m*n) for an
      m*n matrix.
    */
    int T_fact(GF2mat &T, GF2mat &U, ivec &P) const;

    /*! \brief TXP factorization update, when bit is flipped.

    Update upper triangular factor U in the TXP-factorization (U=TXP)
    when the bit at position (r,c) is changed (0->1 or 1->0). The
    purpose of this function is to avoid re-running a complete
    T-factorization when a single bit is changed. The function assumes
    that T, U, and P already exist and that U=TXP before the function
    is called. The function also assumes that the rank provided is
    correct. The function updates T, U and P these matrices.  The
    function returns the new rank of the matrix after the bitflip.

    \note T, U, P and the rank value supplied to the function must be
    correct one. This is not checked by the function (for reasons of
    efficiency).

    The function works by performing permutations to bring the matrix
    to a form where the Gaussian eliminated can be restarted from the
    point (rank-1,rank-1). The function is very fast for matrices with
    close to full rank but it is generally slower for non-full rank
    matrices.
    */
    int T_fact_update_bitflip(GF2mat &T, GF2mat &U,
			      ivec &P, int rank, int r, int c) const;

    /*!  \brief TXP factorization update, when column is added

    Update upper triangular factor U in the T-factorization (U=TXP)
    when a column (newcol) is appended at the right side of the
    matrix.  The purpose of this function is to avoid re-running a
    complete T-factorization when a column is added. The function ONLY
    adds the column if it improves the rank of the matrix (nothing is
    done otherwise).  The function returns "true" if the column was
    added, and "false" otherwise.

    \note This function does not actually add the column newcol to the
    GF2 matrix. It only checks whether doing so would increase the
    rank, and if this is the case, it updates the T-factorization.  A
    typical calling sequence would be
    \code
    bool rank_will_improve =  X.T_fact_update_addcol(T,U,perm,c);
    if (rank_will_improve) { X = X.concatenate_horizontal(c); }
    \endcode

    The complexity is O(m^2) for an m*n matrix.
    */
    bool T_fact_update_addcol(GF2mat &T, GF2mat &U,
			      ivec &P, bvec newcol) const;

    // ----- Operators -----------

    //! Assignment operator
    void operator=(const GF2mat &X);

    //! Check if equal
    bool operator==(const GF2mat &X) const;

    // ----- Friends ------

    //! Multiplication operator
    friend GF2mat operator*(const GF2mat &X, const GF2mat &Y);

    //! Multiplication operator with binary vector
    friend bvec operator*(const GF2mat &X, const bvec &y);

    /*! \brief Addition operator

    Subtraction is not implemented because it is
      equivalent to addition. */
    friend GF2mat operator+(const GF2mat &X, const GF2mat &Y);

    //! Output stream operator (plain text)
    friend std::ostream &operator<<(std::ostream &os, const GF2mat &X);

    //! Write the matrix to file
    friend it_file &operator<<(it_file &f, const GF2mat &X);

    //! Read the matrix from file
    friend it_ifile &operator>>(it_ifile &f, GF2mat &X);

    //!Multiplication X*Y' where X and Y are GF(2) matrices
    friend GF2mat mult_trans(const GF2mat &X, const GF2mat &Y);

  private:
    int nrows, ncols;            // number of rows and columns of matrix
    int nwords;                  // number of bytes used
    Mat<unsigned char> data;		 // data structure

    // This value is used to perform division by bit shift and is equal to
    // log2(8)
    static const unsigned char shift_divisor = 3;

    // This value is used as a mask when computing the bit position of the
    // division remainder
    static const unsigned char rem_mask = (1 << shift_divisor) - 1;
  };


  // ----------------------------------------------------------------------
  // GF2mat related functions
  // ----------------------------------------------------------------------

  /*!
    /relatesalso GF2mat
    /brief Write GF(2) matrix to file.
  */
  it_file &operator<<(it_file &f, const GF2mat &X);

  /*!
    /relatesalso GF2mat
    /brief Read GF(2) matrix from file.
  */
  it_ifile &operator>>(it_ifile &f, GF2mat &X);

  /*!
    \relatesalso GF2mat
    \brief GF(2) matrix multiplication
  */
  GF2mat operator*(const GF2mat &X, const GF2mat &Y);

  /*!
    \relatesalso GF2mat
    \brief GF(2) matrix multiplication with "regular" binary vector
  */
  bvec operator*(const GF2mat &X, const bvec &y);

  /*!
    \relatesalso GF2mat
    \brief GF(2) matrix addition
  */
  GF2mat operator+(const GF2mat &X, const GF2mat &Y);

  /*!
    \relatesalso GF2mat
    \brief Output stream (plain text) operator for dense GF(2) matrices
  */
  std::ostream &operator<<(std::ostream &os, const GF2mat &X);

  /*!
    \relatesalso GF2mat
    \brief GF(2) Identity matrix
  */
  GF2mat gf2dense_eye(int m);

  /*!
    \relatesalso GF2mat
    \brief Multiplication X*Y' where X and Y are GF(2) matrices
  */
  GF2mat mult_trans(const GF2mat &X, const GF2mat &Y);


  // ----------------------------------------------------------------------
  // Inline implementations
  // ----------------------------------------------------------------------

  inline void GF2mat::addto_element(int i, int j, bin s)
  {
    it_assert_debug(i >= 0 && i < nrows, "GF2mat::addto_element()");
    it_assert_debug(j >= 0 && j < ncols, "GF2mat::addto_element()");
    if (s == 1)
      data(i, (j >> shift_divisor)) ^= (1 << (j & rem_mask));
  }

  inline bin GF2mat::get(int i, int j) const
  {
    it_assert_debug(i >= 0 && i < nrows, "GF2mat::get_element()");
    it_assert_debug(j >= 0 && j < ncols, "GF2mat::get_element()");
    return (data(i, (j >> shift_divisor)) >> (j & rem_mask)) & 1;
  }

  inline void GF2mat::set(int i, int j, bin s)
  {
    it_assert_debug(i >= 0 && i < nrows, "GF2mat::set_element()");
    it_assert_debug(j >= 0 && j < ncols, "GF2mat::set_element()");
    if (s == 1) // set bit to one
      data(i, (j >> shift_divisor)) |= (1 << (j & rem_mask));
    else // set bit to zero
      data(i, (j >> shift_divisor)) &= (~(1 << (j & rem_mask)));
  }

} // namespace itpp

#endif // #ifndef GF2MAT_H