### ----------------------------------------------------
### -- Math::Matrix
### -- Licenses: Artistic-2.0
### -- Authors: Pierre Vigier, Herbert Breunung
### -- File: README.md
### ----------------------------------------------------
### -- Chunk 1 of 3
[![Actions Status](https://github.com/raku-community-modules/Math-Matrix/actions/workflows/linux.yml/badge.svg)](https://github.com/raku-community-modules/Math-Matrix/actions) [![Actions Status](https://github.com/raku-community-modules/Math-Matrix/actions/workflows/macos.yml/badge.svg)](https://github.com/raku-community-modules/Math-Matrix/actions) [![Actions Status](https://github.com/raku-community-modules/Math-Matrix/actions/workflows/windows.yml/badge.svg)](https://github.com/raku-community-modules/Math-Matrix/actions)

NAME
====

Math::Matrix - create, compare, compute and measure 2D matrices

SYNOPSIS
========

Matrices are tables with rows and columns (index counting from 0) of numbers (Numeric type - Bool or Int or Num or Rat or FatRat or Complex):

    transpose, invert, negate, add, multiply, dot product, tensor product, 22 ops, determinant, rank, norm
    14 numerical properties, 26 boolean properties, 3 decompositions, submatrix, splice, map, reduce and more

Table of Content:

  * [Methods](#methods)

  * [Operators](#operators)

  * [Export Tags](#export-tags)

  * [Authors](#authors)

  * [License](#license)

DESCRIPTION
===========

Because the list based, functional toolbox of Raku is not enough to calculate matrices comfortably, there is a need for a dedicated data type. The aim is to provide a full featured set of structural and mathematical operations that integrate fully with the Raku conventions. This module is pure Raku and we plan to use native shaped arrays one day.

Matrices are readonly - methods and operators do create new matrix objects. All methods return readonly data or deep clones - also the constructor does a deep clone of provided data. In that sense the library is thread safe.

All computation heavy properties will be calculated lazily and cached. Mathematically or otherwise undefined operations will cause an exception.

[METHODS](#synopsis)
====================

  * **[constructors](#constructors)**: [new []](#new--), [new ()](#new---1), [new ""](#new---2), [new-zero](#new-zero), [new-identity](#new-identity), [new-diagonal](#new-diagonal), [new-vector-product](#new-vector-product)

  * **[accessors](#accessors)**: [element](#element), [AT-POS](#at-pos), [row](#row), [column](#column), [diagonal](#diagonal), [skew-diagonal](#skew-diagonal), [submatrix](#submatrix)

  * **[converter](#converter)**: [Bool](#bool), [Str](#str), [Numeric](#numeric), [Range](#range), [Array](#array), [list](#list), [list-rows](#list-rows), [list-columns](#list-columns), [Hash](#hash), [gist](#gist), [raku](#raku)

  * **[boolean properties](#boolean-properties)**: [zero](#is-zero), [identity](#is-identity), [square](#is-square), [triangular](#is-triangular), [tri-](#is-tridiagonal), [anti-](#is-anti-diagonal), [diagonal](#is-diagonal), [-dominant](#is-diagonally-dominant), [-constant](#is-diagonal-constant), [catalecticant](#is-catalecticant), [anti-](#is-antisymmetric), [symmetric](#is-symmetric), [unitary](#is-unitary), [self-adjoint](#is-self-adjoint), [invertible](#is-invertible), [orthogonal](#is-orthogonal), [positive-definite](#is-positive-definite), [positive-semidefinite](#is-positive-semidefinite)

  * **[numeric properties](#numeric-properties)**: [size](#size), [density](#density), [bandwith](#bandwith), [trace](#trace), [rank](#rank), [nullity](#nullity), [determinant](#determinant), [minor](#minor), [norm](#norm), [condition](#condition), [element-type](#element-type)

  * **[derived matrices](#drived-matrices)**: [transposed](#transposed), [negated](#negated), [conjugated](#conjugated), [adjugated](#adjugated), [inverted](#inverted), [reduced-row-echelon-form](reduced-row-echelon-form)

  * **[decompositions](#decompositions)**: [LU](#LU-decomposition), [LDU](#LU-decomposition), [Cholesky](#Cholesky-decomposition), [LDL](#Cholesky-decomposition)

  * **[math ops](#mathematical-operations)**: [equal](#equal), [add](#add), [multiply](#multiply), [dot-product](#dot-product), [tensor-product](#tensor-product)

  * **[list like ops](#list-like-operations)**: [elems](#elems), [elem](#elem), [cont](#cont), [map](#map), [map-with-index](#map-with-index), [reduce](#reduce), [reduce-rows](#reduce-rows), [reduce-columns](#reduce-columns)

  * **[structural ops](#structural-operations)**: [move-row](#move-row), [move-column](#move-column), [swap-rows](#swap-rows), [swap-columns](#swap-columns), [splice-rows](#splice-rows), [splice-columns](#splice-columns)

  * **[shortcuts](#shortcuts)**: [T](#transposed), [conj](#conjugated), [det](#determinant), [rref](#reduced-row-echelon-form)

  * **[operators](#operator-methods)**: MM, ?, ~, |, @, %, +, -, *, **, dot, ⋅, ÷, X*, ⊗, ==, ~~, ❘ ❘, ‖ ‖, [ ]

[Constructors](#methods)
------------------------

Methods that create a new Math::Matrix object. The default is of course .new, which can take array of array of values (fastest) or one string. Additional constructers: [new-zero](#new-zero), [new-identity](#new-identity), [new-diagonal](#new-diagonal) and [new-vector-product](#new-vector-product) are there for convenience and to optimize property calculation.

### [new( [[...],...,[...]] )](#constructors)

The default constructor, takes arrays of arrays of numbers as the only required parameter. Each second level array represents a row in the matrix. That is why their length has to be the same. Empty rows or columns we not be accepted.

```raku
say Math::Matrix.new( [[1,2],[3,4]] ) :
1 2
3 4

Math::Matrix.new([<1 2>,<3 4>]); # does the same, WARNING: doesn't work with complex numbers
Math::Matrix.new( [[1]] );       # one element 1*1 matrix (exception where you don't have to mind comma)
Math::Matrix.new( [[1,2,3],] );  # one row 1*3 matrix, mind the trailing comma
Math::Matrix.new( [$[1,2,3]] );  # does the same, if you don't like trailing comma
Math::Matrix.new( [[1],[2]] );   # one column 2*1 matrix

use Math::Matrix :MM;            # tag :ALL works too
MM [[1,2],[3,4]];                # shortcut
```

### [new( ((...),...,(...)) )](#constructors)

Instead of square brackets you can use round ones too and use a list of lists as argument too.

```raku
say Math::Matrix.new( ((1,2),(3,4)) );
say MM ((1,2),(3,4)) :
1 2
3 4
```

### [new( "..." )](#constructors)

Alternatively you can define the matrix from a string, which makes most sense while using heredocs.

```raku
Math::Matrix.new("1 2 \n 3 4"); # our demo matrix as string
Math::Matrix.new: q:to/END/;    # indent as you wish
   1 2
   3 4
 END

use Math::Matrix :ALL;          #
MM '1';                         # 1 * 1 matrix, this case begs for a shortcut

=end codd

=head3 L<new-zero|#constructors>

This method is a constructor, that returns a I<zero> matrix, which is sometimes called empty.
That is a matrix, which holds zeros in all its L<element|#element>s (as checked by L<is-zero|#is-zero>).

I<new-zero> needs one ore two integer arguments. These are the numbers of rows and columns -
the size L<size|#size> of the new matrix. If both numbers are the same, you can omit the ladder
and get a L<quadratic|#is-square> matrix filld with zeros.

=begin code :lang<raku>

say Math::Matrix.new-zero( 3, 4 ) :

0 0 0 0
0 0 0 0
0 0 0 0

say Math::Matrix.new-zero( 2 ) :

0 0
0 0
```

### [new-identity](#constructors)

This method creates a new *identity matrix* (as checked by [is-identity](#is-identity)). It contains only zeros, except in the main [diagonal](#diagonal), which consist of ones. Since identity matrices have to be [quadratic](#is-square), *new-identity* requires only one integer arguments, which sets the number of rows and columns of the new matrix.

```raku
say Math::Matrix.new-identity( 3 ) :

1 0 0
0 1 0
0 0 1
```

### [new-diagonal](#constructors)

creates a *diagonal* matrix (as checked by [is-diagonal](#is-diagonal)), which contains zeros, except in the main [diagonal](#diagonal), that can hold arbitrary values. The only required argument is a list these arbitrary numbers, which will become the content of the main diagonal.

```raku
say Math::Matrix.new-diagonal( 2, 4, 5 ) :

2 0 0
0 4 0
0 0 5
```

### [new-vector-product](#constructors)

creates a matrix by calculating the [tensor-product](#tensor-product) of two vectors, which are in a list or Array form the two required arguments of the method. Both lists don't have to be of the same size. The length of the first list will determine the amount of rows and the length of the second the amount of columns.

```raku
say Math::Matrix.new-vector-product([1,2,3],[2,3,4]) :

*    2    3    4
1  1*2  1*3  1*4     2  3  4
2  2*2  2*3  2*4  =  4  6  8
3  3*2  3*3  3*4     6  9 12
```

[Accessors](#methods)
---------------------

Methods that return the content of selected elements.

[element](#element), [AT-POS](#at-pos), [row](#row), [column](#column), [diagonal](#diagonal), [skew-diagonal](skew-diagonal), **[submatrix](submatrix)**: ([leaving out one](#leaving-out-one), [leaving out more](#leaving-out-more), [reordering](#reordering))

### [element](#accessors)

Gets value of one element in [row](#row) (first parameter) and [column](#column) (second parameter - counting always from 0). Sometimes its called matrix cell, to distinct from other type of elements. See: [elems](elems), [elem](elem), [element-type](#element-type)

```raku
my $matrix = Math::Matrix.new([[1,2],[3,4]]);
say $matrix.element(0,1)            : 2
say $matrix[0][1]                   # array syntax alias
```

### [AT-POS](#accessors)

Gets row as array to enable direct postcircumfix syntax as shown in last example.

```raku
say $matrix.AT-POS(0)     : [1,2]
say $matrix[0]            # operator alias
say $matrix.Array[0]      # long alias with converter method Array
```

### [row](#accessors)

returns the values of specified row (first required parameter) as a list.

```raku
say Math::Matrix.new([[1,2],[3,4]]).row(0) : (1, 2)
```

### [column](#accessors)

returns values of specified column (first required parameter) as a list.

```raku
say Math::Matrix.new([[1,2],[3,4]]).column(0) : (1, 3)
```

### [diagonal](#accessors)

Called without an argument, it returns the values of main diagonal as a list. The main diagonal starts at the left upper corner (index [0][0]). Every next cell of the diagonal is reached by going one step below and one step to the right (indices [x][x] - x being an integer within the size of the matrix).

Use the optional parameter of the method to get any other parallel diagonal. A positive value for a parallel diagonale above and to the right of the main one - a negative value to access a parallel diagonal to the left and below the main diagonal. 0 is the default value. The matrix does not have to be a quadratic ([square](#is-square)).

```raku
say Math::Matrix.new([[1,2],[3,4]]      ).diagonal    : (1, 4)
say Math::Matrix.new([[1,2],[3,4]]      ).diagonal(1) : (2)
say Math::Matrix.new([[1,2],[3,4],[5,6]]).diagonal(-1): (3, 6)
```

### [skew-diagonal](#accessors)

Unlike a *diagonal*, which runs from the left upper corner to the right lower, the (main) skew diagonal is only defined for [square](#is-square) matrixes and runs from left lower corner to the right upper (from $matrix[m][0] to $matrix[0][m]). Use the optional argument to get any other parallel skew diagonal. Positive value for the ones below - negative above.

```raku
say $matrix.skew-diagonal    : (2, 3)
say $matrix.skew-diagonal(0) : (2, 3)
say $matrix.skew-diagonal(-1) : (1)
say $matrix.skew-diagonal(1): (4)
```

### [submatrix](#accessors)

Returns a matrix that might miss certain [row](#row)s and columns of the original. This method accepts arguments in three different formats. The first follows the strict mathematical definition of a submatrix, the second supports a rather visual understanding of the term and the third is a way to get almost any combination rows and columns you might wish for. To properly present these functions, we base the next examples upon this matrix:

```raku
say $m:    1 2 3 4
           2 3 4 5
           3 4 5 6
           4 5 6 7
```

#### [leaving out one](#submatrix)

In mathematics, a submatrix is built by leaving out one [row](#row) and one [column](#column). In the two positional argument format you name these by their index ($row, $column).

```raku
say $m.submatrix(1,2) :    1 2 4
                           3 4 6
                           4 5 7
```

#### [leaving out more](#submatrix)

If you provide two ranges (row-min .. row-max, col-min .. col-max - both optional) to the appropriately named arguments, you get the excerpt of the matrix, that contains only the requested rows and columns - in the original order.

```raku
say $m.submatrix( rows => 1..1, columns => 1..2) :    3 4
say $m.submatrix( rows => 1..1, columns => 2..*) :      4 5
say $m.submatrix( rows => 1..2 )                 :  2 3 4 5
                                                    3 4 5 6
```

#### [reordering](#submatrix)

Alternatively each (as previously) named argument can also take a list (or array) of values, as created my the sequence operator (...). The result will be a matrix with that selection of rows and columns. Please note, you may pick rows/columns in any order and as many times you prefer.

```raku
$m.submatrix(rows => (1,2), columns => (3,2)):    5 4
                                                  6 5

$m.submatrix(rows => (1...2), columns => (3,2))  # same thing
```

Arguments with ranges and lists can be mixed and are in both cases optional. If you provide none of them, the result will be the original matrix.

```raku
say $m.submatrix( rows => (1,) )              :   3 4 5

$m.submatrix(rows => (1..*), columns => (3,2)):   5 4
                                                      6 5
```

Even more powerful or explicit in syntax are the [structural ops](#structural-operations).

[Converter](#methods)
---------------------

Methods that convert a matrix into other types: [Bool](#bool), [Str](#str), [Numeric](#numeric), [Range](#range), [Array](#array), [Hash](#hash), [list](#list), [list-rows](#list-rows), [list-columns](#list-columns) or allow different views on the overall content (output formats): [gist](#gist), [raku](#raku).

### [Bool](#converter)

Conversion into Bool context. Returns False if matrix is zero (all elements equal zero as in [is-zero](#is-zero)), otherwise True.

```raku
$matrix.Bool
? $matrix           # alias op
if $matrix          # matrix in Bool context too
```

### [Str](#converter)

Returns values of all [element](#element)s, separated by one whitespace, rows by new line. This is the same format as expected by [new("")](#new---2). Str is called implicitly by put and print. A shortened version is provided by [gist](#gist)

```raku
say Math::Matrix.new([[1,2],[3,4]]).Str:

1 2                 # meaning: "1 2\n3 4"
3 4

~$matrix            # alias op
```

### [Numeric](#converter)

Conversion into Numeric context. Returns Euclidean [norm](#norm). Please note, only a prefix operator + (as in: + $matrix) will call this Method. An infix (as in $matrix + $number) calls $matrix.add($number).

```raku
$matrix.Numeric
+ $matrix           # alias op
```

### [Range](#converter)

Returns an range object that reflects the content of all [element](#element)s. Please note that complex number can not be endpoints of ranges.

```raku
say $matrix.Range: 1..4
```

To get single endpoints you could write:

```raku
say $matrix.Range.min: 1
say $matrix.list.max:  4
```

### [Array](#converter)

Content of all [element](#element)s as an array of arrays (same format that was put into [new([...])](#new--)).

```raku
say Math::Matrix.new([[1,2],[3,4]]).Array : [[1 2] [3 4]]
say @ $matrix       # alias op, space between @ and $ needed
```

### [list](#converter)

Returns a flat list with all [element](#element)s (same as .list-rows.flat.list).

```raku
say $matrix.list    : (1 2 3 4)
say |$matrix        # alias op
```

### [list-rows](#converter)

Returns a list of lists, reflecting the row-wise content of the matrix. Same format as [new ()](#new---1) takes in.

```raku
say Math::Matrix.new( [[1,2],[3,4]] ).list-rows      : ((1 2) (3 4))
say Math::Matrix.new( [[1,2],[3,4]] ).list-rows.flat : (1 2 3 4)
```

### [list-columns](#converter)

Returns a list of lists, reflecting the row-wise content of the matrix.

```raku
say Math::Matrix.new( [[1,2],[3,4]] ).list-columns : ((1 3) (2 4))
say Math::Matrix.new( [[1,2],[3,4]] ).list-columns.flat : (1 3 2 4)
```

### [Hash](#converter)

Gets you a nested key - value hash.

```raku
say $matrix.Hash : { 0 => { 0 => 1, 1 => 2}, 1 => {0 => 3, 1 => 4} }
say % $matrix       # alias op, space between % and $ still needed
```

### [gist](#converter)

Limited tabular view, optimized for shell output. Just cuts off excessive columns that do not fit into standard terminal and also stops after 20 rows. If you call it explicitly, you can add width and height (char count) as optional arguments. Might even not show all decimals. Several dots will hint that something is missing. It is implicitly called by say. For a full view use [Str](#str).

```raku
say $matrix;      # output of a matrix with more than 100 elements

1 2 3 4 5 ..
3 4 5 6 7 ..
...

say $matrix.gist(max-chars => 100, max-rows => 5 );
```

max-chars is the maximum amount of characters in any [row](#row) of output (default is 80). max-rows is the maximum amount of rows gist will put out (default is 20). After gist ist called once (with or without arguments) the output will be cached. So next time you call:

```raku
say $matrix       # 100 x 5 is still the max
```

You change the cache by calling gist with arguments again.

### [raku](#converter)

Conversion into String that can reevaluated into the same object later using default constructor.

```raku
my $clone = $matrix.raku.EVAL;       # same as: $matrix.clone
```

[Boolean Properties](#methods)
------------------------------

These are mathematical properties, a given matrix has or not. Thus, the return value is a always of boolean type (Bool). Arguments, like in case of [triangular](#is-triangular) and [is-diagonally-dominant](#is-diagonally-dominant) are only necessary, when a method can tell you about a group of closely related properties.

[zero](#is-zero), [identity](#is-identity), [square](#is-square), **[triangular](#is-triangular)**: ([upper](#upper-triangular), [lower](#lower-triangular), [strict](#strict-triangular), [unit](#unit-triangular), [atomic](#atomic-triangular)), [diagonal](#is-diagonal), [anti-diagonal](#is-anti-diagonal), [tridiagonal](#is-tridiagonal), [diagonal-constant](#is-diagonal-constant), [catalecticant](#is-catalecticant), [symmetric](#is-symmetric), [anti-symmetric](#is-antisymmetric), [self-adjoint](#is-self-adjoint), [invertible](#is-invertible), [orthogonal](#is-orthogonal), [unitary](#is-unitary), **[diagonally-dominant](#is-diagonally-dominant)**, [positive-definite](#is-positive-definite), [positive-semidefinite](#is-positive-semidefinite)

### [is-zero](#boolean-properties)

True if every [element](#element) has value of 0 (as created by [new-zero](#new-zero)). [Density](#density) of zero matrices is 0. This matrix behaves like a zero element regarding to the [dot-product](#dot-product). Every matrix multiplied with a zero matrix is a zero matrix (A * 0 = 0 * A = 0).

    Example:    0 0 0
                0 0 0

### [is-identity](#boolean-properties)

True if every [element](#element) on the main [diagonal](#diagonal) (where row index equals column index) is 1 and any other element is 0. Such a matrix will be created by [new-identity](#new-identity). It is the neutral element in redgards to the [dot-product](#dot-product). Every matrix multiplied with a fitting identiy matrix results in the same matrix again (A * I = I * A = A). Every identity matrix has to be a square.

    Example:    1 0 0
                0 1 0
                0 0 1

### [is-square](#boolean-properties)

True if number of rows and colums are the same (see [size](#size)).

### [is-triangular](#boolean-properties)

[square](#is-square) matrix where all [element](#element)s above the main [diagonal](#diagonal) or all elements below the main diagonal are zero. The method accepts five optional, boolean arguments: [:upper](#upper-triangular), [:lower](#lower-triangula), [:strict](#strict-triangular), [:unit](#unit-triangular) and [:atomic](#atomic-triangular). Each argument can be used in a positive form (*:upper*), as a negative (*:!upper*), or omitted. Positively they demand a certain property, negatively the absence or opposite. When omitted, both states are acceptable.

Please note that a triangular matrix can never be *:unit* and *:strict* or *:atomic* and *:strict* at the same time, nor *:!upper* and *:!lower*. A triangular matrix that is *:upper* and *:lower* [is-diagonal](#is-diagonal). [Identity](#is-identity) matrices are *:upper*, *:lower* and *:unit*.

#### [upper triangular](#is-triangular)

a.k.a *right triangular matrix*: all [element](#element)s left-below the main *diagonal* are zero. In other words: the [lower-bandwith](#lower-bandwith) has to be zero.

```raku
$tri-matrix.is-triangular(:upper); # matrix in the example below would pass this test
$tri-matrix.is-triangular();       # True, there is a lower or upper triangle

Example:    1 2 5
            0 3 8
            0 0 7
```

#### [lower triangular](#is-triangular)

a.k.a *left triangular* matrix: every [element](#element) right and above the [diagonal](#diagonal) (where [row](#row) index is greater than [column](#column) index) are zero. In other words: the [upper-bandwith](#upper-bandwith) has to be zero.

```raku
$tri-matrix.is-triangular(:lower);        # matrix in the example below would pass this test
$tri-matrix.is-triangular();              # True too
$tri-matrix.is-triangular(:!upper);       # True, because the is a triangle, but not an upper
$tri-matrix.is-triangular(:lower,:!upper);# True still, even a bit redundant

Example:    1 0 0
            2 3 0
            5 8 7
```

#### [strict triangular](#is-triangular)

are *triangular* matrices, that have a [diagonal](#diagonal) consisting only of values equal zero.

```raku
$tri-matrix.is-triangular(:strict);       # matrix in the example below would pass this test
$tri-matrix.is-triangular(:!unit, :lower);# True too

Example:    0 0 0
            5 0 0
            0 6 0
```

#### [unit triangular](#is-triangular)

a.k.a *unitriangular* matrices have a [diagonal](#diagonal) consisting only of values equal one. An [identity](#is-identity) matrix is *:unit*, *:upper* and *:lower*.

```raku
$tri-matrix.is-triangular(:unit);         # matrix in the example below would pass this test
$tri-matrix.is-triangular(:unit, :lower); # False, because unit upper triangular

Example:    1 2 5
            0 1 8
            0 0 1
```

#### [atomic triangular](#boolean-properties)

a.k.a *Frobenius* matrix is a unit triangular matrix with one column of 'none zero values.

```raku
$tri-matrix.is-triangular(:atomic);        # matrix in the example below would pass this test

Example:    1 0 0 0
            0 1 0 0
            0 2 1 0
            0 5 0 1
```

### [is-diagonal](#boolean-properties)

[square](#is-square) matrix, where only elements on the main [diagonal](#diagonal) differ from 0 (as created by [new-diagonal](#new-diagonal)).

```raku
$tri-matrix.is-diagonal();
$tri-matrix.is-triangular(:upper, :lower); # same thing
$tri-matrix.lower-bandwith() == $tri-matrix.upper-bandwith() == 0; # True

Example:    1 0 0
            0 5 0
            0 0 9
```

### [is-anti-diagonal](#boolean-properties)

[square](#is-square) matrix, where only elements on the main [skew-diagonal](#skew-diagonal) differ from 0.

```raku
$tri-matrix.is-anti-diagonal();

Example:    0 0 3
            0 5 0
            7 0 0
```

### [is-tridiagonal](#boolean-properties)

[square](#is-square) matrix, where only elements on the main [diagonal](#diagonal) and their direct parallels differ from 0.

```raku
$tri-matrix.is-tridiagonal();
$tri-matrix.lower-bandwith() < 2 and $tri-matrix.upper-bandwith() < 2; # True

Example:    1 2 0 0
            3 4 5 0
            0 6 7 8
            0 0 9 1
```

### [is-diagonal-constant](#boolean-properties)

a.k.a. or *Töplitz* matrix is a matrix where every [diagonal](#diagonal) is the a collection of [element](#element)s that hold the same value.

        Example:     0  1  2
                    -1  0  1
                    -2 -1  0

### [is-catalecticant](#boolean-properties)

a.k.a *Hankel* matrix is a [square](#is-square) matrix, where every [skew-diagonal](#skew-diagonal) is the a collection of [element](#element)s that hold the same value. *Catalecticant* matrices are [symmetric](#is-symmetric).

    Example:     0  1  2
                 1  2  3
                 2  3  4

### [is-symmetric](#boolean-properties)

True if every [element](#element) with coordinates x y has same value as the element on y x. In other words: $matrix and $matrix.[transposed](#transposed) (alias T) are the same.

    Example:    1 2 3
                2 5 4
                3 4 7

### [is-antisymmetric](#boolean-properties)

Means the [transposed](#transposed) and [negated](#negated) matrix are the same.

    Example:    0  2  3
               -2  0  4
               -3 -4  0

### [is-self-adjoint](#boolean-properties)

A Hermitian or self-adjoint matrix is [equal](#equal) to its [transposed](#transposed) and complex [conjugated](#conjugated).

    Example:    1   2   3+i
                2   5   4
                3-i 4   7

### [is-invertible](#boolean-properties)

, also called *nonsingular* or *nondegenerate*, is a [square](#is-square) matrix, which has a none zerot [determinant](#determinant). That means all rows or colums have to be independent vectors. Please check this property before calling $matrix.[inverted](#inverted), or you will get an exception.

### [is-orthogonal](#boolean-properties)

An orthogonal matrix multiplied ([dot-product](#dot-product)) with its transposed derivative (T) is an [identity](#is-identity) matrix or in other words: [transposed](#transposed) and [inverted](#inverted) matrices are [equal](#equal).

### [is-unitary](#boolean-properties)

An unitery matrix multiplied ([dot-product](#dot-product)) with its [concjugated](#conjugated) and transposed derivative (.conj.T) is an [identity](#is-identity) matrix, or said differently: the concjugate transposed matrix equals the [inverted](#inverted) matrix.

### [is-diagonally-dominant](#boolean-properties)

True when [element](#element)s on the [diagonal](#diagonal) have a bigger (if strict) or at least equal (in none strict) absolute value than the sum of its row (sum of absolute values of the row except diagonal element).

```raku
if $matrix.is-diagonally-dominant {
$matrix.is-diagonally-dominant(:!strict)      # same thing (default)
$matrix.is-diagonally-dominant(:strict)       # diagonal elements (DE) are stricly greater (>)
$matrix.is-diagonally-dominant(:!strict, :along<column>) # default
$matrix.is-diagonally-dominant(:strict,  :along<row>)    # DE > sum of rest row
$matrix.is-diagonally-dominant(:!strict, :along<both>)   # DE >= sum of rest row and rest column
```

### [is-positive-definite](#boolean-properties)

True if all main [minors](#minor) or all Eigenvalues are strictly greater zero.

### [is-positive-semidefinite](#boolean-properties)

True if all main [minors](#minor) or all Eigenvalues are greater equal zero.

[Numeric Properties](#methods)
------------------------------

Matrix properties that are expressed with a single number, which will be calculated without further input.

[size](#size), [density](#density), **[bandwith](#bandwith)**: ([lower-](#lower-bandwith), [upper-](#upper-bandwith)), [trace](#trace), [rank](#rank), [nullity](#nullity), [determinant](#determinant), [minor](#minor), [norm](#norm), [condition](#condition), **[element-type](#element-type)**