The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Math::FastGF2::Matrix - Matrix operations for fast Galois Field arithmetic

SYNOPSIS

 use Math::FastGF2::Matrix;
 
 $m=Math::FastGF2::Matrix->
   new(rows => $r, cols => $c, width => $w, org => "rowwise");
 $i=Math::FastGF2::Matrix->
   new_identity(size => $size, width => $w, org => "rowwise");
 $copy=$m->copy( ... );
 $copy=$m->copy_rows($row1, $row2, ... );
 $copy=$m->copy_cols($col1, $col2, ... );
 $copy=$m->submatrix($row1,$col1,$row2,$col2);
 $copy=$m->flip(...);
 $copy=$m->transpose;
 $copy=$m->reorganise;

 $rows = $m->ROWS;   $cols  = $m->COLS;
 $org  = $m->ORG;    $width = $m->WIDTH;
 
 $val=$m->getval($row,$col);
 $m->setval($row,$col,$val);
 $m->zero;
 
 @vals=$m->getvals($row,$col,$words,$order);
 $vals=$m->getvals($row,$col,$words,$order);
 $vals=$m->setvals($row,$col,\@vals,$order);
 $vals=$m->setvals($row,$col,$vals,$order);
 
 $product=$m->multiply($m);
 $inverse=$m->invert;
 $adjoined=$m->concat($m);
 $solution=$m->solve;

DESCRIPTION

This module provides basic functionality for handling matrices of Galois Field elements. It is a fairly "close to the metal" implementation using the C language to store the underlying object and handle performance-critical tasks such as bulk input/output of values and matrix multiplication. Less critical tasks are handled by Perl methods.

All matrix elements are treated as polynomials in GF(2^m), with all calculations on them being done using the Math::FastGF2 module.

CONSTRUCTORS

new

New Math::FastGF2::Matrix objects are created and initialised to with zero values with the new() constructor method:

 $m=Math::FastGF2::Matrix->
   new(rows => $r, cols => $c, width => $w, org => "rowwise");

The rows and cols parameters specify how many rows and columns the new matrix should have. The width parameter must be set to 1, 2 or 4 to indicate Galois Fields of that many bytes in size.

The org parameter is optional and defaults to "rowwise" if unset. This parameter specifies how the matrix should be organised in memory, which affects how the bulk data input/output routines setvals and getvals enter data and retrieve it from the matrix. With "rowwise" organisation, values are written in left-to-right order first, moving down to the next row as each row becomes full. With "colwise" organisation, values are written top-to-bottom first, moving right to the next column as each column becomes full.

new_identity

To create a new identity matrix with $size rows and columns, width $w and organisation $org:

 $i=Math::FastGF2::Matrix->
          new_identity(size => $size, width => $w, org => $org);

As with the new constructor, the org parameter is optional and default to "rowwise".

new_cauchy

Create a Cauchy matrix from a set of x and y values:

 my @xvals = (1..7);        # all values must be distinct across
 my @yvals = (8..10);       # the combined list
 
 # Passing separate x and y lists (rows/cols inferred)
 $i=Math::FastGF2::Matrix->
          new_cauchy(width => 1, org => "rowwise",
                     xvals => \@xvals, yvals => \@yvals
          );

 # Passing combined list and at least one of rows/cols
 $i=Math::FastGF2::Matrix->
          new_cauchy(width => 1, org => "rowwise",
                     xyvals => [@xvals, @yvals],
                     rows => scalar(@xvals),
                     cols => scalar(@yvals),
          );

Cauchy matrices have the useful property that for a matrix of n rows and k columns, all subsets of k rows are linearly independent with respect to each other. Thus this submatrix is invertible. This has applications in constructing error-correcting codes. See the Crypt::IDA manual page for details.

new_inverse_cauchy

Creates an inverse Cauchy matrix from a set of y values and an subset of x values:

 my @xvals = (20..27);        # all values must be distinct across
 my @yvals = (28..30);        # the combined list
 
 $i=Math::FastGF2::Matrix->
      new_inverse_cauchy(width => 1, org => "rowwise",
                         xylist => [ @xvals, @yvals ],
                         size => 3,       # size of y list
                         xvals => [0..3], # indexes into x list
 );

Note that the xvals parameter in this case is a set of indices into the @xvals array. Effectively, it selects 'size' rows from the Cauchy matrix described by [ @xvals, @yvals ] and inverts that matrix.

This uses an algorithm described in volume 1 of Knuth's "The Art of Computer Programming", which should run faster than the regular Gaussian elimination method implemented by the invert method.

new_vandermonde

Create a Vandermonde matrix from a list of x values

 $i=Math::FastGF2::Matrix->
      new_vandermonde(width => 1, org => "rowwise",
                      xvals => [ 0..6 ],  # 7 rows
                      cols   => 3,
 );

For each x_i value, creates a row of the form:

        |     0    1    2          cols-1  |
        |   x    x    x   ...    x         |
        |    i    i    i          i        |

If all the x_i values in the list are distinct, then, like the Cauchy matrix above, taking any 'cols' subset of rows from the matrix gives you an invertible matrix. This is the form of matrix generally used for Reed-Solomon error-correcting codes.

To create the inverse of some cols x cols submatrix, just use the standard invert method on it.

copy

The copy method copy of some or all elements of an existing matrix. The template for a call, showing the default values of all parameters is as follows:

 $new_matrix = $m->copy(
         rows => undef,         # [ $row1, $row2, ... ]
         cols => undef,         # [ $col1, $col2, ... ]
         submatrix => undef,    # [ $row1, $col1, $row2, $col2 ]
 );

If no parameters are set, then then the entire matrix is copied. The rows and cols parameters can be set individually or in combination with each other, to copy only the selected rows or columns to the new matrix. The submatrix parameter copies a rectangular region of the original matrix into the new matrix. The submatrix option cannot be used in combination with the rows or cols options.

The new matrix will have the same values set for the width and org parameters as the original matrix.

The copy_rows, copy_cols and submatrix methods are implemented as small wrapper functions which call the copy method with the appropriate parameters.

copy_rows

 $new_matrix = $m->copy_rows ($row1, $row2, ... );

Create a new matrix from the selected rows of the original matrix.

copy_cols

 $new_matrix = $m->copy_cols ($col1, $col2, ... );

Create a new matrix from the selected columns of the original matrix.

submatrix

 $new_matrix = $m->submatrix ($row1, $col1, $row2, $col2);

Create a new matrix from the selected rectangular region of the original matrix.

transpose

Return a new matrix which is the transpose of the original matrix. The organisation of the original matrix is carried over to the new matrix:

 $new_matrix = $m->transpose;

reorganise

Return a new matrix which has the opposite organisation to the original matrix:

 $new_matrix = $m->reorganise;

flip

Carry out transpose and/or reorganise operations in one step:

 $new_matrix = $m->flip( transpose = > (0 or 1),
                         org => ("rowwise" or "colwise") );

The org parameter is the organisation to use for the new matrix.

GETTING AND SETTING VALUES

Getting and setting individual values in the matrix is handled by the getval and setval methods:

 $val=$m->getval($row,$col);
 $m->setval($row,$col,$val);

Multiple values can be got/set at once, using the more efficient getvals/setvals methods:

 @vals=$m->getvals($row,$col,$words,$order);
 $vals=$m->getvals($row,$col,$words,$order);
 $vals=$m->setvals($row,$col,\@vals,$order);
 $vals=$m->setvals($row,$col,$vals,$order);

These methods copy the values out of/into the C data structure. The $words parameter to getvals specifies how many values to extract from the Matrix.

These methods can take an optional $order parameter which can be used to perform byte-swapping on 2-byte and 4-byte words where it is needed. The possible values are:

0. input is/output should be in native byte order (no byte-swapping)
1. input is/output should be in little-endian byte order
2. input is/output should be in big-endian byte order

Examples

To swap two rows of a "rowwise" matrix using temporary lists

 die "Expected matrix to be ROWWISE\n" unless $m->ORG eq "rowwise"
 @list1 = $m->getvals($row1,0,$m->COLS);
 @list2 = $m->getvals($row2,0,$m->COLS);
 $m->setvals($row1,0,\@list2);
 $m->setvals($row2,0,\@list1);

The same example using slightly more efficient string form:

 die "Expected matrix to be ROWWISE\n" unless $m->ORG eq "rowwise"
 $str1 = $m->getvals($row1,0,$m->COLS);
 $str2 = $m->getvals($row2,0,$m->COLS);
 $m->setvals($row1,0,$str2);
 $m->setvals($row2,0,$str1);

This is an example of how not to implement the above. It fails because getvals is being called in a list context. Beware:

 ($str1,$str2) = ( $m->getvals($row1,0,$m->COLS),
                   $m->getvals($row2,0,$m->COLS) );
 $m->setvals($row1,0,$str2);
 $m->setvals($row2,0,$str1);

Likewise, this common idiom also implies a list context:

 my ($var) = ...

When in doubt about list/scalar context, always use a simple assignment to a scalar variable. Alternatively, scalar context can be enforced by using Perl's scalar keyword, eg:

 my ($str) = (scalar $m->getvals(...));

Read in some little-endian values from a file, and have them converted to Perl's internal format if necessary:

 # assume ROWWISE, writing values into row $row of matrix
 sysread $fh, $str, $m->COLS * $m->WIDTH;
 $m->setvals($row,0,$str,1);

Take values from a matrix and output them to a file as a list of little-endian values:

 # assume ROWWISE, reading values from row $row of matrix
 $str=$m->getvals($row,0,$str,1);
 syswrite $fh, $str, $m->COLS * $m->WIDTH;

Zero all elements in a matrix (works regardless of matrix organisation):

 $m->setvals(0,0,(0) x ($m->ROWS * $m->COLS));

or:

  $m->setvals(0,0,"\0" x ($self->ROWS * $self->COLS * $self->WIDTH));

(which is exactly what the zero method does.)

MATRIX OPERATIONS

Multiply

To multiply two matrices $m1 (on left) and $m2 (on right), use:

 $result=$m1->multiply($m2);

This returns a new matrix in $result or undef on error. The number of columns in $m1 must equal the number of rows in $m2. The resulting matrix will have the same number of rows as $m1 and the same number of columns as $m2. An alternative form allows storing the result in an existing matrix (of the appropriate dimensions), thus avoiding the overhead of allocating a new one:

 $m1->multiply($m2,$result);

The $result matrix is also returned, though it can be safely ignored.

Invert

To invert a square matrix (using Gauss-Jordan method):

 $inverse=$m->invert;

A new inverse matrix is returned if the matrix was invertible, or undef otherwise.

Concat(enate)

To create a new matrix which has matrix $m1 on the left and $m2 on the right, use:

$adjoined = $m1->concat($m2);

The number of rows in $m1 and $m2 must be the same. Returns a new matrix or undef in the case of an error.

Solve

Treat matrix as a set of simultaneous equations and attempt to solve it using Gaussian elimination:

 $solution=$m->solve;

The result is a new matrix, or undef if the equations have no solution. The input matrix must have at least one more column than rows, with the first $m->ROWS columns being the coefficients of the equations to be solved (ie, the left-hand side of equations), and the remaining column(s) being the value(s) the equations evaluate to (ie, the right-hand side of equations).

Equality

To test whether two matrices have the same values:

 if ($m1->eq($m2)) {
   # Matrices are equal
   ...
 }

Testing for inequality:

 if ($m1->ne($m2)) {
   # Matrices are not equal
   ...
 }

SEE ALSO

See Math::FastGF2 for details of the underlying Galois Field arithmetic.

See Math::Matrix for storing and manipulating matrices of regular numbers.

AUTHOR

Declan Malone, <idablack@users.sourceforge.net>

COPYRIGHT AND LICENSE

Copyright (C) 2009-2019 by Declan Malone

This package is free software; you can redistribute it and/or modify it under the terms of the "GNU General Public License" ("GPL").

Please refer to the file "GNU_GPL.txt" in this distribution for details.

DISCLAIMER

This package 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.