# NAME

Math::MatrixLUP - Matrix operations and LUP decomposition.

# VERSION

Version 0.03

# 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 is 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 is 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 is 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 is 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 is 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);`

For negative `n`

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

# * 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.

## vflip / vertical_flip

Returns a new matrix with rows flipped.

## hflip / horizontal_flip

Returns a new matrix with columns flipped.

## transpose

Returns the transposed matrix. This is a new matrix where columns and rows of the self-matrix are swapped.

## 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;`

## invmod

Invert a square matrix modulo a positive integer.

` my $B = $A->invmod($m);`

## 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

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.