Daniel Șuteu

NAME

Math::MatrixLUP - Matrix operations and LUP decomposition.

VERSION

Version 0.02

SYNOPSIS

    use Math::MatrixLUP;
    use Math::AnyNum qw(:overload);

    my $A = Math::MatrixLUP->new([
        [2, -1,  5,  1],
        [3,  2,  2, -6],
        [1,  3,  3, -1],
        [5, -2, -3,  3],
    ]);

    my $det = $A->determinant;
    my $sol = $A->solve([-3, -32, -47, 49]);
    my $inv = $A->invert;
    my $pow = $A**3;
    my $pwm = $A->powmod(100, 10000019);
    my $mod = $A % 10007;

DESCRIPTION

Math::MatrixLUP provides generic support for matrix operations and LUP decomposition, allowing any type of numbers inside the matrix, including native Perl numbers and numerical objects provided by other mathematical libraries, such as Math::AnyNum.

The following matrix operations are provided:

  • matrix-scalar arithmetical operations

  • matrix multiplication and division

  • matrix exponentiation

  • determinant of a square-matrix

  • inverting a square-matrix

  • solving a system of linear equations

Math::MatrixLUP objects are immutable.

METHODS

new

Create a new Math::MatrixLUP object, given a 2D array-ref:

    my $A = Math::MatrixLUP->new([
            [rand,rand,rand],
            [rand,rand,rand],
            [rand,rand,rand],
    ]);

identity / I

Returns a nXn identity matrix, given an integer argument:

    my $I = Math::MatrixLUP->I(3);
    my $I = Math::MatrixLUP->identity(3);

build

Build a new nXm matrix, given two integers and a subroutine reference as arguments:

    my $A = Math::MatrixLUP->build($n, $m, sub ($i, $j) {
        $i * $j
    });

If only one integer is given, it creates a square nXn matrix:

    my $B = Math::MatrixLUP->build($n, sub ($i, $j) {
        $i**$j
    });

The values of i (row number) and j (column number) range from [0, n-1] and [0, m-1].

zero

Returns a new nXm matrix with all entries set to 0.

    my $A = Math::MatrixLUP->zero(3);       # 3x3 zero-matrix
    my $A = Math::MatrixLUP->zero(3, 4);    # 3x4 zero-matrix

scalar

Returns a new square matrix with the diagonal set a given value.

    my $A = Math::MatrixLUP->scalar(3, 42);  # 3x3 scalar with value 42

from_rows

A construct method that creates a new matrix, given a list of array-ref rows:

    my $A = Math::MatrixLUP->from_rows(
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    );

from_columns

A construct method that creates a new matrix, given a list of array-ref columns:

    my $A = Math::MatrixLUP->from_columns(
        [1, 4, 7],
        [2, 5, 8],
        [3, 6, 9],
    );

set_row

Returns a new matrix with the n-th (zero-based) row set to the given array-ref of values:

    my $B = $A->set_row(0, [1,2,3,4]);      # set first row

set_column

Returns a new matrix with the n-th (zero-based) column set to the given array-ref of values:

    my $B = $A->set_column(0, [1,2,3,4]);   # set first column

row

A constructor method that creates a row vector, given a single array-ref of numbers.

    my $row_vector = Math::MatrixLUP->row([1, 4, 4, 8]);

When called on a matrix object, it returns the n-th row (zero-based) as an array-ref.

    my $row = $A->row(0);     # first row as an array-ref

rows

Returns the rows of the matrix as an array of array-refs.

    my @rows = $A->rows;

column

A constructor method that creates a column vector, given a single array-ref of numbers.

    my $column_vector = Math::MatrixLUP->column([1, 4, 4, 8]);

When called on a matrix object, it returns the n-th column (zero-based) as an array-ref.

    my $col = $A->column(0);  # first column as an array-ref

columns

Returns the columns of the matrix as an array of array-refs.

    my @columns = $A->columns;

diagonal

A constructor method that creates a diagonal matrix from a single array-ref of numbers.

    my $A = Math::MatrixLUP->diagonal([1, 4, 4, 8]);

The matrix is zero filled except for the diagonal, which take the value of the given vector.

When called on a matrix object, it returns the diagonal as an array-ref:

    my $diag = $A->diagonal;

anti_diagonal

A constructor method that creates an anti-diagonal matrix from a single array-ref of numbers.

    my $A = Math::MatrixLUP->anti_diagonal([1, 4, 4, 8]);

The matrix is zero filled except for the anti-diagonal, which take the value of the given vector.

When called on a matrix object, it returns the anti-diagonal as an array-ref:

    my $diag = $A->anti_diagonal;

* Arithmetic operations

neg

Returns a new matrix with all the terms negated.

    my $B = -$A;
    my $B =  $A->neg;

abs

Returns a new matrix with the abs() function applied to all terms.

    my $B = abs($A);
    my $B = $A->abs;

floor

Returns a new matrix with the floor() function applied to all terms.

    my $B = $A->floor;

ceil

Returns a new matrix with the ceil() function applied to all terms.

    my $B = $A->ceil;

add

Add two matrices of the same dimensions:

    my $C = $A + $B;
    my $C = $A->add($B);

If one of the arguments it not a Math::MatrixLUP object, scalar addition is performed:

    my $B = $A + $scalar;

sub

Subtract two matrices of the same dimensions:

    my $C = $A - $B;
    my $C = $A->sub($B);

If one of the arguments it not a Math::MatrixLUP object, scalar subtraction is performed:

    my $B = $A - $scalar;
    my $B = $scalar - $A;

mul

Multiplication of two matrices, where the number of columns in A equals the number of rows in B.

    my $C = $A * $B;
    my $C = $A->mul($B);

If one of the arguments it not a Math::MatrixLUP object, scalar multiplication is performed:

    my $B = $A * $scalar;

div

Division of two matrices.

    my $C = $A / $B;
    my $C = $A->div($B);

Defined as:

    A/B = A * B^(-1)

If one of the arguments it not a Math::MatrixLUP object, scalar division is performed:

    my $B = $A / $scalar;
    my $B = $scalar / $A;

mod

Modulo operation.

    my $C = $A % $B;
    my $C = $A->mod($B);

Defined as:

    A mod B = A - B*floor(A/B)

If one of the arguments it not a Math::MatrixLUP object, scalar modulo is performed:

    my $B = $A % $scalar;
    my $B = $scalar % $A;

pow

Matrix exponentiation, where the exponent is a native integer:

    my $B = $A**$n;
    my $B = $A->pow($n);

For negative n, this operation is defined only if the matrix can be inverted.

powmod

Matrix exponentiation modulo m, where the exponent is an arbitrary large positive integer:

    my $B = $A->powmod($n, $m);

Negative exponents are not supported yet.

* Bitwise operations

This section includes method for scalar and entrywise matrix bitwise operations.

lsft / rsft / or / xor / and

Bitwise scalar operations:

    my $B = $A->lsft(2);  # left-shift by 2 applied to each value
    my $B = $A->rsft(2);  # right-shift by 2 applied to each value
    my $B = $A->or(2);    # OR 2 applied to each value
    my $B = $A->xor(2);   # XOR 2 applied to each value
    my $B = $A->and(2);   # AND 2 applied to each value

Entrywise bitwise operations:

    my $C = $A->lsft($B);     # entrywise left-shift
    my $C = $A->rsft($B);     # entrywise right-shift
    my $C = $A->or($B);       # entrywise OR
    my $C = $A->xor($B);      # entrywise XOR
    my $C = $A->and($B);      # entrywise AND

* Transformations

flip

Returns a new matrix with rows and columns flipped.

vertical_flip

Returns a new matrix with rows flipped.

horizontal_flip

Returns a new matrix with columns flipped.

transpose

Returns the transposed matrix. This is the matrix where colums and rows of the argument matrix are swaped.

concat

Concatenates two matrices of same row count. The result is a new matrix.

map

Map each entry of a matrix to a given subroutine callback.

    my $B = $A->map(sub { $_**2 });  # new matrix with each entry squared

The subroutine is called with $i and $j as arguments, such that $_ = $A->[$i][$j].

* Comparisons

eq / ne

Decide if two matrices are equal or not.

    $A == $B      # true if equal
    $A != $B      # true if not equal

lt / le / gt / ge / cmp

Compare two matrices, entrywise:

    $A  <  $B      # true if A is less than B
    $A  <= $B      # true if A is less than or equal to B
    $A  >  $B      # true if A is greater than B
    $A  >= $B      # true if A is greater than or equal to B
    $A <=> $B      # -1 if A < B, 0 if A == B, 1 if A > B

* Linear algebra

solve

Solve a system of linear equations.

    my $A = Math::MatrixLUP->new([
        [2, -1,  5,  1],
        [3,  2,  2, -6],
        [1,  3,  3, -1],
        [5, -2, -3,  3],
    ]);

    my $solution = $A->solve([-3, -32, -47, 49]);
    say join(', ', @{$solution});  #=> 2, -12, -4, 1

inv / invert

Invert a square matrix.

    my $B = $A->inv;

det / determinant

Compute the determinant of a square matrix.

rref

Returns the reduced row echelon form of the self-matrix.

    my $B = $A->rref;

decompose

Returns the LUP decomposition of the self matrix.

    my ($N, $A, $P) = $matrix->decompose;

There is no need to call this method explicitly. It is called internally automatically and is cached at object-level.

* Other methods

clone

Returns a deep copy of the self-matrix.

size

Returns the dimensions of the matrix (1-based):

    my ($rows, $cols) = $A->size;

* Conversions

as_array

Returns the matrix as a 2D array-ref.

stringify

Retruns a stringified version of the self-matrix.

OVERLOADING

The entries of a Math::MatrixLUP object can be accessed as an array-ref:

    my $Aij = $A->[$i][$j];

However, modifying the matrix in-place is not recommended, as Math::MatrixLUP uses dynamic caching at object-level in order to avoid recomputing the LUP decomposition multiple times for the same matrix-object.

SEE ALSO

  • Related libraries

    Math::Matrix - Multiply and invert matrices.

    Math::GSL::Matrix - Mathematical functions concerning Matrices using the GNU Scientific Library (GSL).

    Math::MatrixDecomposition::LU - LU decomposition with partial pivoting of a real matrix.

    Math::AnyNum - Arbitrary size precision for integers, rationals, floating-points and complex numbers.

REPOSITORY

https://github.com/trizen/Math-MatrixLUP

REFERENCES

https://en.wikipedia.org/wiki/LU_decomposition

AUTHOR

Daniel Șuteu, <trizen at cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2019 Daniel Șuteu

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.22.0 or, at your option, any later version of Perl 5 you may have available.