txt: ## dist_zef-raku-community-modules-Math-Matrix.md
  ## Chunk 2 of 3
   distance of a none zero value from the main [diagonal](#diagonal). A matrix that [is-diagonal](#is-diagonal) has a bandwith of 0. If there is a none zero value on an diagonal above or below the main diagonal, tha bandwith would be one.
  
  ```
  my $bw = $matrix.bandwith;
  
  ```
  
  #### [lower-bandwith](#bandwith)
  
  In a matrix with the lower bandwith of k, every [element](#element) with row index m and column index n, for which holds m - k > n, the content has to be zero. Literally speaking: there are k [diagonal](#diagonal)s below the main diagonal, that contain none zero values.
  
  #### [upper-bandwith](#bandwith)
  
  Analogously, every [element](#element) with m + k < n is zero if matrix has an upper bandwith of k.
  
  ```
  Example:    1  0  0
              4  2  0
              0  5  3
  
  ```
  
  The *bidiagonal* example matrix has an upper bandwith of zero and lower bandwith of one, so the overall bandwith is one.
  
  ### [trace](#numeric-properties)
  
  The trace of a [square](#is-square) matrix is the sum of the [element](#element)s on the main diagonal. In other words: sum of elements which row and column value is identical.
  
  ```
  my $tr = $matrix.trace;
  
  ```
  
  ### [rank](#numeric-properties)
  
  Rank is the number of independent row or column vectors or also called independent dimensions (thats why this command is sometimes calles dim)
  
  ```
  my $r = $matrix.rank;
  
  ```
  
  ### [nullity](#numeric-properties)
  
  Nullity of a matrix is the number of dependent rows or columns (rank + nullity = dim). Or number of dimensions of the kernel (vector space mapped by the matrix into zero).
  
  ```
  my $n = $matrix.nullity;
  
  ```
  
  ### [determinant](#numeric-properties)
  
  Only a [square](#is-square) matrice has a defined determinant, which tells the volume, spanned by the row or column vectors. So if the volume is just in one dimension flat, the determinant is zero, and has a kernel (not a full [rank](#rank) - thus is not [invertible](#is-invertable)).
  
  ```
  my $det = $matrix.determinant;
  my $d = $matrix.det;                # same thing
  my $d = ❘ $matrix ❘;                # unicode operator shortcut
  
  ```
  
  ### [minor](#numeric-properties)
  
  A Minor is the determinant of a [submatrix](#leaving-out-one) (first variant with same 2 scalar arguments a minor method). The two required positional arguments are row and column indices of an existing [element](#element).
  
  ```
  my $m = $matrix.minor(1,2);
  
  ```
  
  ### [norm](#numeric-properties)
  
  A norm is a single positive number, which is an abstraction to the concept of size. Most common form for matrices is the p-norm, where in step 1 the absolute value of every [element](#element) is taken to the power of p. The sum of these results is taken to the power of 1/p. The p-q-Norm extents this process. In his step 2 every column-sum is taken to the power of (p/q). In step 3 the sum of these are taken to the power of (1/q).
  
  ```
  my $norm = $matrix.norm( );           # euclidian norm aka L2 (p = 2, q = 2)
  my $norm = + $matrix;                 # context op shortcut
  my $norm = ‖ $matrix ‖;               # unicode op shortcut
  my $norm = $matrix.norm(1);           # p-norm aka L1 = sum of all elements absolute values (p = 1, q = 1)
  my $norm = $matrix.norm(p:<4>,q:<3>); # p,q - norm, p = 4, q = 3
  my $norm = $matrix.norm(p:<2>,q:<2>); # L2 aka Euclidean aka Frobenius norm
  my $norm = $matrix.norm('euclidean'); # same thing, more expressive to some
  my $norm = $matrix.norm('frobenius'); # same thing, more expressive to some
  my $norm = $matrix.norm('max');       # maximum norm - biggest absolute value of a element
  $matrix.norm('row-sum');              # row sum norm - biggest abs. value-sum of a row
  $matrix.norm('column-sum');           # column sum norm - same column wise
  
  ```
  
  ### [condition](#numeric-properties)
  
  Condition number of a matrix is L2 norm \* L2 of [inverted](#inverted) matrix.
  
  ```
  my $c = $matrix.condition( );
  
  ```
  
  ### [element-type](#numeric-properties)
  
  #### [narrowest-element-type](#numeric-properties)
  
  #### [widest-element-type](#numeric-properties)
  
  Matrix [element](#element)s can be (from most narrow to widest), of type (Bool), (Int), (Num), (Rat), (FatRat) or (Complex). The widest type of any element will returned as type object.
  
  In the next example the smartmatch returns true, because no element of our default example matrix has wider type than (Int). After such a test all elements can be safely treated as Int or Bool.
  
  ```
  if $matrix.widest-element-type ~~ Int { ...
  
  ```
  
  You can also check if all elements have the same type:
  
  ```
  if $matrix.widest-element-type eqv $matrix.narrowest-element-type
  
  ```
  
  ## [Derived Matrices](#methods)
  
  Single matrices, that can be computed with only our original matrix as input.
  
  [transposed](#transposed), [negated](#negated), [conjugated](#conjugated), [adjugated](#adjugated), [inverted](#inverted), [reduced-row-echelon-form](#reduced-row-echelon-form)
  
  ### [transposed](#derived-matrices)
  
  Returns a new, transposed Matrix, where rows became colums and vice versa.
  
  ```
  Math::Matrix.new([[1,2,3],[3,4,6]]).transposed :
  
  [[1 2 3]     = [[1 4]
   [4 5 6]].T     [2 5]
                  [3 6]]
  
  Math::Matrix.new([[1,2,3],[3,4,6]]).T # same but shorter
  
  ```
  
  ### [negated](#derived-matrices)
  
  Creates a matrix where every [element](#element) has the negated value of the original (invertion of sign).
  
  ```
  my $new = $matrix.negated();     # invert sign of all elements
  my $neg = - $matrix;             # operator alias
  
  say $neg:  -1 -2
             -3 -4
  
  ```
  
  ### [conjugated](#derived-matrices)
  
  Creates a matrix where every [element](#element) is the complex conjugated of the original.
  
  ```
  my $c = $matrix.conjugated();    # change every value to its complex conjugated
  my $c = $matrix.conj();          # short alias (official Raku shortcut for conjugation of numbers)
  
  say Math::Matrix.new([[1+i,2],[3,4-i]]).conj :
  
  1-1i  2
  3     4+1i
  
  my $ct = $matrix.H;              # conjugated and transposed matrix (Hermitian transpose)
  
  ```
  
  ### [adjugated](#derived-matrices)
  
  Creates a matrix out of the properly signed [minors](#minor) of the original. It is called adjugate, classical adjoint or sometimes adjunct.
  
  ```
  $matrix.adjugated.say :
  
   4 -3
  -2  1
  
  ```
  
  ### [inverted](#derived-matrices)
  
  Matrices that have a [square](#is-square) form and a full [rank](#rank) can be [inverted](#inverted) (see [is-invertible](#is-invertible)). Inverse matrix regarding to matrix multiplication (see [dot-product](#dot-product)). The dot product of a matrix with it's inverted results in a [identity](#is-identity) matrix (neutral element in this group).
  
  ```
  my $i = $matrix.inverted();      # invert matrix
  my $i = $matrix ** -1;           # operator alias
  
  say $i:
  
   -2    1
  1.5 -0.5
  
  ```
  
  ### [reduced-row-echelon-form](#derived-matrices)
  
  Return the reduced row echelon form of a matrix, a.k.a. row canonical form
  
  ```
  my $rref = $matrix.reduced-row-echelon-form();
  my $rref = $matrix.rref();       # short alias
  
  ```
  
  ## [Decompositions](#methods)
  
  Methods that return a list of matrices, which can be recombined into the original matrix (mostly by [dot product](#dot-product)).
  
  [LU](#LU-decomposition), [LU-Crout](#LU-Crout-decomposition), [LDU](#LDU-decomposition), [LUP](#LUP-decomposition), [Cholesky](#Cholesky-decomposition) [LDL](#LDL-decomposition)
  
  ### [LU-decomposition](#decompositions)
  
  Decompose an [invertible](#is-invertible), matrix into a [lower triangular](#is-lower-triangular) (called L) and an [upper triangular matrix](#is-upper-triangular) (called U). The algorithm works along the lines of what is called Gaussian elimination.
  
  ```
  my ($L, $U) = $matrix.LU-decomposition();
  $L dot $U eq $matrix;                # True
  $U.is-triangular(:upper);             # True
  $L.is-triangular(:lower, :unit);       # True
  
  ```
  
  #### [LU-Crout-decomposition](#decompositions)
  
  L will also be [unit triangular matrix](#unit-triangular), but not U - meaning the [diagonal](#diagonal) elements of L are all equal 1 and the diagonal elements of U might differ from 1. If you prefer this to be the other way around, use the optional, boolean parameter *:Crout*.
  
  ```
  my ($L, $U) = $matrix.LU-decomposition(:Crout);
  $L dot $U eq $matrix;                # True
  $L.is-triangular(:lower);             # True
  $U.is-triangular(:upper, :unit);       # True
  
  ```
  
  #### [LDU-decomposition](#decompositions)
  
  If you want the diagonal elements separated into its own matrix, use the optional, boolean parameter *:diagonal*. Note that you can not use this and *:Crout* at once.
  
  ```
  my ($L, $D, $U) = $matrix.LU-decomposition( :diagonal);
  $L dot $D dot $U eq $matrix;         # True
  $L.is-triangular(:lower, :unit);      # True
  $U.is-triangular(:upper, :unit);       # True
  $D.is-diagonal();                       # True
  
  ```
  
  #### [LUP-decomposition](#decompositions)
  
  If you choose the optional, boolean parameter *:pivot*, you get additionally a permutation matrix, that contains the information which rows and columns were swapped, in order to achieve a decomposition. That is why the matrix no longer has to be [invertible](#is-invertable), but only [square](#is-square) to run a LU decomposition with permutation. This option might be combined with *:Crout* or *:diagonal*, but not both.
  
  ```
  my ($L, $U, $P) = $matrix.LU-decomposition( :pivot );
  $L dot $U eq $matrix dot $P;         # True
  
  ```
  
  ### [Cholesky-decomposition](#decompositions)
  
  This decomposition does roughly the same as LU and is faster. But it works only on matrices that are [symmetric](#is-symmetric) and [positive-definite](#is-positive-definite). The result will be an [orthogonal](#is-orthogonal), [lower triangular matrix](#is-lower-triangular) matrix (here called G) that multiplied with its [transposed](#transposed) gives you the original matrix.
  
  ```
  my $G = $matrix.Cholesky-decomposition( );          # $G is a left triangular matrix
  my $G = $matrix.Cholesky-decomposition(:!diagonal); # same as before
  $G dot $G.T == $matrix;                             # True
  
  ```
  
  #### [LDL-decomposition](#decompositions)
  
  When the optional, boolean parameter :diagonal is positive (negative by default) you get two matrices (L and D) as a result. L is then a [lower unit triangular matrix](#unit-triangular), (with ones in its main diagonal). D is a [diagonal](#diagonal) matrix ( G = L \* sqrt(D)), containing the values formerly on the diagonal of G, but squared. This output format is also known as *LDL decomposition*. You get the second L matrix easily by transposing the L you got.
  
  ```
  my ($L, $D) = $matrix.Cholesky-decomposition(:diagonal);
  $L dot $D dot $L.T == $matrix;                      # True
  
  ```
  
  ## [Mathematical Operations](#methods)
  
  Math methods that work on a whole matrix or just some parts of it. The operands will not be changed but a the result matrix will be returned.
  
  [equal](#equal), **[add](#add)**: ([matrix](#add-matrix), [vector](#add-vector), [scalar](#add-scalar)), **[multiply](#multiply)**: ([matrix](#multiply-matrix), [vector](#multiply-vector), [scalar](#multiply-scalar)), [dot-product](#dot-product), [tensor-product](#tensor-product).
  
  ### [equal](#mathematical-operations)
  
  Checks two matrices for equality. They have to be of same [size](#size) and every [element](#element) of the first matrix on a particular position has to be numerically equal (as checked by *==*) to the element (on the same position) of the second matrix.
  
  ```
  if $matrixa.equal( $matrixb ) {   # method variant
  if $matrixa == $matrixb {         # operator alias
  if $matrixa ~~ $matrixb {         # smart match redirects to ==
  
  ```
  
  ### [add](#mathematical-operations)
  
  Adding a matrix, [vector](#add-vector) or [scalar](#scalar-scalar). Named arguments *:row* and *:column* are only used to add a vector (one) or scalar (both).
  
  #### [add matrix](#add)
  
  When adding two matrices, they have to be of the same [size](#size). Instead of a Math::Matrix object you can also provide the content of a matrix as [new []](#new--), [new ()](#new---1) or [new ""](#new---2) would accept it.
  
  ```
  $matrix.add( $matrix2 );
  $matrix.add( [[2,3],[4,5]] ); # data alias
  $matrix + $matrix2            # operator alias
  
  Example:    1 2  +  2 3  =  3 5
              3 4     4 5     7 9
  
  ```
  
  #### [add vector](#add)
  
  To add a vector you have to specify to which row or column it should be added. The other argument is a list or array (which have to fit the row or column size).
  
  ```
  $matrix.add( row => 1, [2,3] );
  
  Example:    1 2  +       =  1 2
              3 4    2 3      5 7
  
  $matrix.add( column => 1, (2,3) );
  
  Example:    1 2  +   2   =  1 4
              3 4      3      3 7
  
  ```
  
  #### [add scalar](#add)
  
  When adding a single number to the matrix (providing one argument), the number will be added to every [element](#element) of the matrix. If you additionally provide a row or column number, only in that row or column, every element gets added to. In case you provide row and column numbber (three args), only a single element of the result matrix might be different.
  
  ```
  $matrix.add( $number );       # adds number to every element
  $matrix + $number;            # works too
  
  Example:    1 2  +  5    =  6 7
              3 4             8 9
  
  $matrix.add( row => 1, 3 ):             [[1,2],[6,7]]
  $matrix.add( row => 1, column=> 0, 2 ): [[1,2],[5,4]]
  
  ```
  
  ### [multiply](#mathematical-operations)
  
  Unlike the [dot-product](#dot-product) and [tensor-product](#tensor-product), this operation is the simple, scalar multiplication applied to each ore some [element](#element)s. The second factor might come from the cells of another [matrix](#multiply-matrix), a [vector](#multiply-vector) or a [single value](#multiply-scalar). That is why this method works analogous to [add](#add).
  
  #### [multiply matrix](#multiply)
  
  When a matrix of same size is given, the result will be a matrix of that size again. Each element will be the product of two the two elements of the operands with the same indices (position). Instead of a Math::Matrix object you can also provide the content of a matrix as [new []](#new--), [new ()](#new---1) or [new ""](#new---2) would accept it.
  
  ```
  my $product = $matrix.multiply( $matrix2 );  # element wise multiplication of same size matrices
  my $p = $matrix * $matrix2;                  # works too
  
  Example:    1 2  *  2 3  =   2  6
              3 4     4 5     12 20
  
  ```
  
  #### [multiply vector](#multiply)
  
  Takes a vector (list of numbers) and a Pair thst specifies an existing row or column. This row or column will than multiplied with the vector (element one by vector element one, and so on).
  
  ```
  my $product = $matrix.multiply( row => 0, (2, 3) );   # multiply every element with number
  
  Example:    1 2  *  2 3  =  2 6
              3 4             3 4
  
  ```
  
  #### [multiply scalar](#multiply)
  
  If you provide just one number, every matrix element will be multiplied by this number. When you additionally add a valid row or column index, only the cells in that row or column get multiplied. (This is especially useful, when doing Gaussian elimination.) If both are provided, only one cell gets multiplied.
  
  ```
  my $product = $matrix.multiply( $number );   # multiply every element with number
  my $p = $matrix * $number;                   # does the same
  
  Example:    1 2  *  5    =   5 10
              3 4             15 20
  
  $matrix.multiply( row => 0, 2);
  
  Example:    1 2  * 2     =  2 4
              3 4             3 4
  
  $matrix.multiply(2, column => 0 );
  
  Example:    1 2   =  2 2
              3 4      6 4
  
             *2
  
  $matrix.multiply(row => 1, column => 1, 3) : [[1,2],[3,12]]
  
  ```
  
  ### [dot-product](#mathematical-operations)
  
  Matrix multiplication of two fitting matrices (colums left == rows right).
  
  ```
  Math::Matrix.new( [[1,2],[3,4]] ).dot-product(  Math::Matrix.new([[2,3],[4,5]]) );
  
  Example:    2  3
              4  5
           *
       1 2   10 13  =  1*2+2*4  1*3+2*5
       3 4   22 29     3*2+4*4  3*3+4*5
  
  my $product = $matrix1.dot-product( $matrix2 )
  my $c = $a dot $b;              # works too as operator alias
  my $c = $a ⋅ $b;                # unicode operator alias
  
  A shortcut for multiplication is the power - operator **
  my $c = $a **  3;               # same as $a dot $a dot $a
  my $c = $a ** -3;               # same as ($a dot $a dot $a).inverted
  my $c = $a **  0;               # created an right sized identity matrix
  
  ```
  
  ### [tensor-product](#mathematical-operations)
  
  The *tensor product* (a.k.a *Kronecker product*) between a matrix A of *size|#size* (m,n) and matrix B of size (p,q) is a matrix C of size (m*p,n*q). C is a concatination of matrices you get if you take every [element](#element) of A and do a [scalar multiplication](#multiply) with B as in $B.multiply($A.element(..,..)).
  
  ```
  Example:    1 2  X*  2 3   =  1*[2 3] 2*[2 3]  =  2  3  4  6
              3 4      4 5        [4 5]   [4 5]     4  5  8 10
                                3*[2 3] 4*[2 3]     6  9  8 12
                                  [4 5]   [4 5]     8 15 16 20
  
  my $c = $matrixa.tensor-product( $matrixb );
  my $c = $a X* $b;               # works too as operator alias
  my $c = $a ⊗ $b;                # unicode operator alias
  
  ```
  
  ## [List Like Operations](#methods)
  
  Methods (or extensions thereof) that usually are provided by Lists and Arrays, but make also sense in context of matrices: [elems](#elems), [elem](#elem), [cont](#cont), [map](#map), [map-with-index](#map-with-index), [reduce](#reduce), [reduce-rows](#reduce-rows), [reduce-columns](#reduce-columns)
  
  ### [elems](#list-like-operations)
  
  Number (count) of [element](#element)s = rows \* columns (see [size](#size)).
  
  ```
  say $matrix.elems();
  
  ```
  
  ### [elem](#list-like-operations)
  
  Asks if all [element](#element) of Matrix (cell) values are an element of the given set or range.
  
  ```
  Math::Matrix.new([[1,2],[3,4]]).elem(1..4) :   True
  Math::Matrix.new([[1,2],[3,4]]).elem(2..5) :   False, 1 is not in 2..5
  
  ```
  
  ### [cont](#list-like-operations)
  
  Asks if the matrix contains a value equal to the only argument of the method. If a range is provided as argument, at least one value has to be within this range to make the result true.
  
  ```
  Math::Matrix.new([[1,2],[3,4]]).cont(1)   : True
  Math::Matrix.new([[1,2],[3,4]]).cont(5)   : False
  Math::Matrix.new([[1,2],[3,4]]).cont(3..7): True
  
  MM [[1,2],[3,4]] (cont) 1                 # True too
  
  ```
  
  ### [map](#list-like-operations)
  
  Creates a new matrix of same size by iterating over all or some [element](#element)s. For every chosen element with the indices (m,n), a provided code block (required argument) will be run once. That block will be given the elements(m,n) value as an argument. The return value of the block will be the content of the element(m,n) of the resulting matrix.
  
  ```
  say $matrix.map(* + 1) :
  
  2 3
  4 5
  
  ```
  
  By provding values (Ranges) to the named arguments *rows* and *columns* (no special order required), only a subset of rows or columns will be mapped - the rest will be just copied.
  
  ```
  say $matrix.map( rows => (0..0), {$_ * 2}) :
  
  2 4
  3 4
  
  say $matrix.map( rows => (1..*), columns => (1..1), {$_ ** 2}) :
  
  1  2
  3 16
  
  ```
  
  ### [map-with-index](#list-like-operations)
  
  Works just like [map](#map) with the only difference that the given block can recieve one to three arguments: (row index, column index and cell value).
  
  ```
  say $matrix.map-with-index: {$^m == $^n ?? $^value !! 0 } :
  
  1 0
  0 4
  
  ```
  
  ### [reduce](#list-like-operations)
  
  Like the built in reduce method, it iterates over all [element](#element)s and joins them into one value, by applying the given operator or method to the previous result and the next element. I starts with the element [0][0] and moving from left to right in the first row and continue with the first element of the next row.
  
  ```
  Math::Matrix.new([[1,2],[3,4]]).reduce(&[+]): 10 = 1 + 2 + 3 + 4
  Math::Matrix.new([[1,2],[3,4]]).reduce(&[*]): 10 = 1 * 2 * 3 * 4
  
  ```
  
  ### [reduce-rows](#list-like-operations)
  
  Reduces (as described above) every row into one value, so the overall result will be a list. In this example we calculate the sum of all elements in a row:
  
  ```
  say Math::Matrix.new([[1,2],[3,4]]).reduce-rows(&[+]): (3, 7)
  
  ```
  
  ### [reduce-columns](#list-like-operations)
  
  Similar to reduce-rows, this method reduces each column to one value in the resulting list:
  
  ```
  say Math::Matrix.new([[1,2],[3,4]]).reduce-columns(&[*]): (3, 8)
  
  ```
  
  ## [Structural Operations](#methods)
  
  Methods that reorder rows and columns, delete some or even add new. The accessor [submatrix](#submatrix) is also useful for that purpose. [move-row](#move-row), [move-column](#move-column), [swap-rows](#swap-rows), [swap-rows](#swap-columns), [splice-rows](#splice-rows), [splice-columns](#splice-columns)
  
  ### [move-row](#structural-matrix-operations)
  
  ```
  Math::Matrix.new([[1,2,3],[4,5,6],[7,8,9]]).move-row(0,1);  # move row 0 to 1
  Math::Matrix.new([[1,2,3],[4,5,6],[7,8,9]]).move-row(0=>1); # same
  
  1 2 3           4 5 6
  4 5 6    ==>    1 2 3
  7 8 9           7 8 9
  
  ```
  
  ### [move-column](#structural-matrix-operations)
  
  ```
  Math::Matrix.new([[1,2,3],[4,5,6],[7,8,9]]).move-column(2,1);
  Math::Matrix.new([[1,2,3],[4,5,6],[7,8,9]]).move-column(2=>1); # same
  
  1 2 3           1 3 2
  4 5 6    ==>    4 6 5
  7 8 9           7 9 8
  
  ```
  
  ### [swap-rows](#structural-matrix-operations)
  
  ```
  Math::Matrix.new([[1,2,3],[4,5,6],[7,8,9]]).swap-rows(2,0);
  
  1 2 3           7 8 9
  4 5 6    ==>    4 5 6
  7 8 9           1 2 3
  
  ```
  
  ### [swap-columns](#structural-matrix-operations)
  
  ```
  Math::Matrix.new([[1,2,3],[4,5,6],[7,8,9]]).swap-columns(0,2);
  
  1 2 3           3 2 1
  4 5 6    ==>    6 5 4
  7 8 9           9 8 7
  
  ```
  
  ### [splice-rows](#structural-matrix-operations)
  
  Like the splice for lists: the first two parameter are position and amount (optional) of rows to be deleted. The third and alos optional parameter will be an array of arrays (line .new would accept), that fitting row lengths. These rows will be inserted before the row with the number of first parameter. The third parameter can also be a fitting Math::Matrix.
  
  ```
  $matrix.splice-rows(0,0, Math::Matrix.new([[5,6],[7,8]]) ); # aka prepend
  $matrix.splice-rows(0,0,                  [[5,6],[7,8]]  ); # same result
  
  5 6
  7 8
  1 2
  3 4
  
  $matrix.splice-rows(1,0, Math::Matrix.new([[5,6],[7,8]]) ); # aka insert
  $matrix.splice-rows(1,0,                  [[5,6],[7,8]]  ); # same result
  
  1 2
  5 6
  7 8
  3 4
  
  $matrix.splice-rows(1,1, Math::Matrix.new([[5,6],[7,8]]) ); # aka replace
  $matrix.splice-rows(1,1,                  [[5,6],[7,8]]  ); # same result
  
  1 2
  5 6
  7 8
  
  $matrix.splice-rows(2,0, Math::Matrix.new([[5,6],[7,8]]) ); # aka append
  $matrix.splice-rows(2,0,                  [[5,6],[7,8]]  ); # same result
  $matrix.splice-rows(-1,0,                 [[5,6],[7,8]]  ); # with negative index
  
  1 2
  3 4
  5 6
  7 8
  
  ```
  
  ### [splice-columns](#structural-matrix-operations)
  
  Same as splice-rows, just horizontally.
  
  ```
  $matrix.splice-columns(2,0, Math::Matrix.new([[5,6],[7,8]]) ); # aka append
  $matrix.splice-columns(2,0,                  [[5,6],[7,8]]  ); # same result
  $matrix.splice-columns(-1,0,                 [[5,6],[7,8]]  ); # same result with negative index
  
  1 2  ~  5 6  =  1 2 5 6
  3 4     7 8     3 4 7 8
  
  ```
  
  ## [Shortcuts](#methods)
  
  Summary of all shortcut aliases (left) and their long form (right).
  
  * T --> [transposed](#transposed)
  * H --> [conjugated and transposed](#conjugated)
  * conj --> [conjugated](#conjugated)
  * det --> [determinant](#determinant)
  * rref --> [reduced-row-echelon-form](#reduced-row-echelon-form)
  
  ## [Operator Methods](#methods)
  
  Operators (left) with the methods they refer to (right). (Most ops are just aliases.) For more explanations of the ops (with examples) see the [next chapter](#operators):
  
  * prefix ? --> [Bool](#bool)
  * prefix + --> [Numeric](#numeric)
  * prefix - --> [negated](#negated)
  * prefix ~ --> [Str](#str)
  * prefix | --> [list](#list)
  * prefix @ --> [Array](#array)
  * prefix % --> [Hash](#hash)
  * prefix MM --> [new](#new--)
  * infix == --> [equal](#equal)
  * infix ~~ --> [equal](#equal) ACCEPTS
  * infix + --> [add](#add)
  * infix - --> [add](#add)
  * infix \* --> [multiply](#multiply)
  * infix ⋅ dot --> [dot-product](#dot-product)
  * infix ÷ --> dot-product [inverted](#inverted)
  * infix \*\* --> dot-product inverted
  * infix ⊗ X\* --> [tensor-product](#tensor-product)
  * circumfix ｜..｜ --> [determinant](#determinant)
  * circumfix ‖..‖ --> [norm](#norm)
  * postcircumfix [..] --> [AT-POS](#at-pos)
  
  # [Operators](#synopsis)
  
  The Module overloads or introduces a range of well and lesser known ops, which are almost all [aliases](#operator-methods).
  
  ==, +, \* are commutative, -, ⋅, dot, ÷, x, ⊗ and \*\* are not. All ops have same precedence as its multi method siblings - unless stated otherwise.
  
  They are exported when using no flag (same as :DEFAULT) or :ALL, but not under :MANDATORY or :MM). The only exception is MM operator, a shortcut to create a matrix. That has to be importet explicitly with the tag :MM or :ALL. The postcircumfix [] - op will always work.
  
  ```
  my $a   = +$matrix               # Num context, Euclidean norm
  my $b   = ?$matrix               # Bool context, True if any element has a none zero value
  my $str = ~$matrix               # String context, matrix content, space and new line separated as table
  my $l   = |$matrix               # list context, list of all elements, row-wise
  my $a   = @ $matrix              # same thing, but as Array
  my $h   = % $matrix              # hash context, similar to .kv, so that %$matrix{0}{0} is first element
  
  $matrixa == $matrixb             # check if both have same size and they are element wise equal
  $matrixa ~~ $matrixb             # same thing
  
  my $sum =  $matrixa + $matrixb;  # element wise sum of two same sized matrices
  my $sum =  $matrix  + $number;   # add number to every element
  
  my $dif =  $matrixa - $matrixb;  # element wise difference of two same sized matrices
  my $dif =  $matrix  - $number;   # subtract number from every element
  my $neg = -$matrix               # negate value of every element
  
  my $p   =  $matrixa * $matrixb;  # element wise product of two same sized matrices
  my $sp  =  $matrix  * $number;   # multiply number to every element
  
  my $dp  =  $a dot $b;            # dot product of two fitting matrices (cols a = rows b)
  my $dp  =  $a ⋅ $b;              # dot product, unicode (U+022C5)
  my $dp  =  $a ÷ $b;              # alias to $a dot $b.inverted, (U+000F7)
  
  my $c   =  $a **  3;             # $a to the power of 3, same as $a dot $a dot $a
  my $c   =  $a ** -3;             # alias to ($a dot $a dot $a).inverted
  my $c   =  $a **  0;             # creats an right sized identity matrix
  
  my $tp  =  $a X* $b;             # tensor product, same precedence as infix: x (category Replication)
  my $tp  =  $a ⊗ $b;              # tensor product, unicode (U+02297)
  
   ｜$matrix ｜                     # determinant, unicode (U+0FF5C)
   ‖ $matrix ‖                     # L2 norm (euclidean p=2 to the square), (U+02016)
  
     $matrix[1][2]                 # 2nd row, 3rd column element - works even under :MANDATORY tag
  
  MM