• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[System] Matrices

Level 14
Joined
Dec 12, 2012
Messages
1,007
Matrix operations are a very basic concept in Mathematics and many problems can be solved easy and elegant with them. Unfortunatly Warcraft 3 does not provide any of them, so this system aims to close this gap and provide various methods to deal with matrices.

Enclosed is the system code:

JASS:
library Matrices /* v 1.4.0.0
**********************************************************************************
*
*   Matrices
*   ¯¯¯¯¯¯¯¯ 
*   By looking_for_help aka eey
*
*   This system provides advanced methods for handling Matrices in Warcraft 3.
*   Features like Matrix multiplication, calculation of norms or trace as well as
*   solving a system of linear equations with Gauss-Elimination are implemented.
*   The system also provides a big variety of functions to initialize, copy or
*   reshape Matrices.
*
*   Credits go to Magtheridon for helping with the Systems API.
*  
**********************************************************************************
*
*   Requirements
*   ¯¯¯¯¯¯¯¯¯¯¯¯
*   */  uses Maths   /*  hiveworkshop.com/forums/spells-569/advanced-maths-ingame-calculator-234024/?prev=r%3D20%26page%3D5
*
**********************************************************************************
*
*   Implementation
*   ¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*   To use this system just copy it into an empty trigger in your map. As this
*   system uses the Math library you should install it first to get the system
*   to work. The Math library can be found under the link above.
*
**********************************************************************************
*
*   System API
*   ¯¯¯¯¯¯¯¯¯¯ 
*
*   Struct usage
*   -----------------------------
*
*       struct Matrix
*           - This struct provides the methods and logic to use Matrices in 
*             Warcraft 3 with this system. Use the create method to allocate a 
*             new instance of a Matrix of your desired size. The Matrix can then 
*             be used like a 2D-Array (example displayed above) and provides  
*             various methods to perform advanced Matrix operations.
*                             
*                                                          0  1  2    
*                                                       0 [0][0][0]
*             local Matrix mat = Matrix.create(3, 3) =  1 [0][0][0]
*                                                       2 [0][0][0]
*
*
*   Operators
*   -----------------------------
*
*       [] operators
*           - Use the [] operators to access directly to the values of a given 
*             Matrix. For example mat[2][1] will return the element in the third 
*             row, second column. Note that the indices are, like Wc3 arrays, 
*             zero-based.
*
*
*   Fields
*   -----------------------------
*
*       readonly integer n
*           - Specifies the number of rows of a given Matrix.
*
*       readonly integer m
*           - Specifies the number of columns of a given Matrix.
*
*       readonly static Matrix Invalid_Matrix
*           - An invalid Matrix of the size 0 x 0. You can't create such a Matrix, 
*             so if you need one, use this field. Some algorithms, such as solveSLE 
*             return such a Matrix if no solution for a given System of Linear 
*             Equations could be found. You can use the method isValid() to 
*             determine wether a Matrix is valid or not.       
*
*       static constant integer ONE_NORM
*           - Use this as a parameter for the norm method to specify that the method
*             should calculate the one norm (maximum of column sum absolute values).
*
*       static constant integer EUCLIDEAN_NORM
*           - Use this as a parameter for the norm method to specify that the method
*             should calculate the euclidean norm (square root of sum of squares).
*
*       static constant integer INFINITY_NORM
*           - Use this as a parameter for the norm method to specify that the method
*             should calculate the infinity norm (maximum of row sum absolute values).
*
*       static constant integer METHOD_ROW_WISE
*           - Use this as a parameter for methods like initStepWise or reShape to
*             specify whether the method should be applied row-wise.
*
*       static constant integer METHOD_COL_WISE
*           - Use this as a parameter for methods like initStepWise or reShape to
*             specify whether the method should be applied col-wise.
*
*
*   Methods
*   -----------------------------
*
*       static method create takes integer nDim, integer mDim returns Matrix
*           - Creates a new n x m Matrix with the maximum size of MAX_MATRIX_SIZE
*             (specified in the globals block). The Matrix is initialized with 
*             zeros.
*
*       method destroy takes nothing returns nothing
*           - Destroys a given Matrix to free its memory usage.
*  
*       method display takes nothing returns nothing
*           - Use this method to display a Matrix ingame. This is especially 
*             meant for debugging issues.
*
*       method isValid takes nothing returns boolean
*           - Checks whether a given Matrix is valid (means: not empty) or not.
*
*       method isEqual takes Matrix mat returns boolean
*           - Checks whether two Matrices are equal or not. If A == B then
*             A.isEqual(B) returns true.
*
*       method init takes real value returns nothing
*           - Use this method to initialize a Matrix with a desired real value. 
*             Note that this method does not create a new instance of the Matrix 
*             object, as well as all methods that only initialize the values of a 
*             Matrix.
*
*       method eye takes nothing returns nothing
*           - Use this method to initialize an Identity Matrix.
*
*       method diag takes real value, integer whichDiagonal returns nothing
*           - Use this method to initialize a Diagonal Matrix with a desired real
*             value. Use the second argument to specify which diagonal you want
*             to set (zero is the main diagonal, negative values address the 
*             upper, positive values the lower diagonals).
*
*       method rand takes real lowerBound, real upperBound returns nothing
*           - Use this method to initialize a Matrix with random real values.
*
*       method initStepWise takes real startValue, real steps returns nothing
*           - Use this method to initialize a matrix from a given start value in
*             ascending or descending order specified by the steps parameter.
*
*       method assign takes nothing returns Matrix
*           - Use this method to assign a Matrix to another Matrix. For example
*             set B = A.assign() will copy A to B. Note that A and B must be of
*             equal size for this operation to work.
*
*       method addScalar takes real value returns Matrix
*           - This method performs a element-wise addition of a given real value
*             and returns the new Matrix. Example: A.addScalar(2.0) will add the
*             value 2.0 to all elements of the Matrix A.
*
*       method subScalar takes real value returns Matrix
*           - This method performs a element-wise subtraction of a given real 
*             value.
*
*       method multScalar takes real value returns Matrix
*           - This method performs a element-wise multiplication by a given real
*             value.
*
*       method divScalar takes real value returns Matrix
*           - This method performs a element-wise division by a given real value.
*
*       method abs takes nothing returns Matrix
*           - This method performs the abs function on all Matrix elements.
*
*       method add takes Matrix whichMatrix returns Matrix
*           - Matrix addition. The expression A.add(B) where both A and B are
*             Matrices returns the resulting Matrix A + B. Note that the Matrices
*             must follow common Matrix calculation rules, like here that A and B
*             have the same size.
*
*       method sub takes Matrix whichMatrix returns Matrix
*           - Matrix substraction. Same as the add method, A.sub(B) performs 
*             A - B.
*
*       method multiply takes Matrix whichMatrix returns Matrix
*           - Matrix multiplication. The expression A.multiply(B) performs the
*             operation A*B. Note that A's number of columns must equal B's 
*             number of rows for this operation to be well-defined.
*
*       method transpose takes nothing returns Matrix
*           - Matrix transposition. The expression A.transpose() computes A^T.
*
*       method invert takes nothing returns Matrix
*           - Matrix inversion. Use A.invert() to calculate A^-1, the inverse 
*             of the Matrix A. Be aware of the fact that not every Matrix is
*             invertable.
*
*       method gauss takes nothing returns Matrix
*           - Use this method to perform a Gauss-Elimination with pivotising.
*             The result is a upper triangular Matrix.
*
*       method solveSLE takes Matrix b returns Matrix
*           - Use this method to solve a System of Linear Equations following
*             the common notation A*x = b. To calculate x use A.solveSLE(b) 
*             where A is the system Matrix and b is the solution vector. If the 
*             SLE has no unique solution, an invalid vector of size 0 x 0 is 
*             returned.
*
*       method dotProduct takes Matrix b returns real
*           - Use this method to calculate the dot product of two Vectors. Use
*             it like a.dotProduct(b), which results in a^T*b. Calling this
*             method is faster than performing the transposition manualy and
*             should therefore be used if possible. To check whether two Vectors
*             are orthogonal, the dot product must be zero.
*
*       method crossProduct takes Matrix b returns Matrix
*           - Use this method to calculate the cross product of two Vectors.
*             This implementation only supports calculation of cross products
*             for Vectors in R^3.
*
*       method trace takes nothing returns real
*           - Returns the trace of a given Matrix. Which is defined as the sum 
*             over its diagonal elements.
*
*       method det takes nothing returns real
*           - Returns the determinant of a given Matrix. From A.det() == 0 
*             follows for example that A is not invertable.
*
*       method rank takes nothing returns integer
*           - Returns the rank of a given Matrix. A square Matrix must have full 
*             rank to be invertable, which means that A.rank() == A.n must return
*             true.
*
*       method norm takes integer whichNorm returns real
*           - Computes the norm of a given Matrix. You can choose between different
*             norms by using the constants defined in the Matrix struct. Valid 
*             values for the whichNorm parameter are ONE_NORM, EUCLIDEAN_NORM 
*             and the INFINITY_NORM.
*
*       method cond takes integer whichNorm returns real
*           - Computes the condition of a Matrix. You can specify which Norm you 
*             want to use for that purpose by the parameter whichNorm (see method 
*             norm). Note that the Matrix must be invertable otherwise the 
*             condition will be infinity.
*
*       method kron takes Matrix mat returns Matrix
*           - Computes the Kronecker Product of two Matrices. The result of for
*             example A.kron(B) where A is a n x m and B is a p x q Matrix is
*             a n*p x m*q Matrix. As you see this operation potentially produces
*             very big Matrices so use it with care.
*
*       method subMatrix takes integer startRow, integer startCol, integer endRow, 
*                        integer endCol returns Matrix
*           - This method can be used to get a sub Matrix out of another Matrix.
*             With the parameters startRow and startCol you can specify where
*             the submatrix should begin and the parameters endRow as well as
*             endCol define where to end the sub Matrix. If A is for example
*             a 3 x 3 Matrix, A.subMatrix(0, 0, 2, 0) will return the first
*             column Vector of A, while A.subMatrix(0, 0, 1, 1) will return
*             the first 2 x 2 sub Matrix of A and so on.
*
*       method embed takes Matrix subMat, integer startRow, integer startCol 
*                    returns Matrix
*           - This method embeds one Matrix into another. If you have for example
*             the 3 x 3 Matrix A and the 2 x 2 Matrix B then A.embed(B, 0, 0)
*             will assign the upper left sub matrix of A to the values of B. The 
*             parameters startRow and startCol specify where the embeding should 
*             start. Of course the sub matrix must fit into the Matrix you want to 
*             embed it into, otherwise an error will be thrown.
*
*       method concatH takes Matrix mat returns Matrix
*           - Use this method to concatenate two Matrices. The Matrices must
*             have the same amount of rows for this operation to work. The Matrices
*             will get concatenated horizontal, resulting for  two n x m
*             Matrices in a n x 2*m Matrix. Example: A.concatH(B) will concate-
*             nate A to B (from the left side).
*
*       method concatV takes Matrix mat returns Matrix
*           - Use this method to concatenate two Matrices. The Matrices must
*             have the same amount of columns for this operation to work. The 
*             Matrices will get concatenated vertically, resulting for two n x m
*             Matrices in a 2*n x m Matrix. Example: A.concatV(B) will stack
*             the Matrix B on A.
*
*       method reShape takes integer newN, integer newM, integer whichMethod 
*                      returns Matrix
*           - Use this method to reshape a Matrix. If you have for example a
*             3 x 2 Matrix A, by performing A.reShape(2, 3, METHOD_ROW_WISE)
*             the Matrix will get a 2 x 3 Matrix. The third parameter whichMethod
*             determines whether the operation should be done row-wise or
*             column-wise. METHOD_ROW_WISE and METHOD_COL_WISE are valid
*             parameters. This can also be used to make a Vektor of a Matrix
*             (or vice versa): A.reShape(6, 1, METHOD_COL_WISE) will stack
*             all column Vektors of A to one 6 x 1 Vektor.
*
*       method switchRow takes integer whichRow, integer newRow returns Matrix
*           - Use this method to switch two different rows of a Matrix. The  
*             expression A.switchRow(0, 2) will switch the first with the third 
*             row. Note that both parameters whichRow and newRow must not exceed 
*             Matrix dimensions.
*
*       method switchCol takes integer whichCol, integer newCol returns Matrix
*           - Use this method to switch two different columns of a Matrix. Same
*             rules as for switchRow apply here.
*  
*********************************************************************************/

    globals
        /*************************************************************************
        *   Configurable globals
        *************************************************************************/
    
        // Accuracy for considering a Matrix too close to singularity
        private constant real EPSILON = 0.01 
    
        // Biggest possible n x n-Matrix
        private constant integer MAX_MATRIX_SIZE = 30
        
        /*************************************************************************
        *   End of configurable globals
        *************************************************************************/
    endglobals

    private struct MatrixRow
        real array values[MAX_MATRIX_SIZE]
        integer maxCols
    
        method operator [] takes integer column returns real
            debug call ThrowError(this == 0, "Matrices", "[]", "MatrixRow", this, "Attempt to access null reference!")
            return this.values[column]
        endmethod

        method operator []= takes integer column, real value returns nothing
            debug call ThrowError(this == 0, "Matrices", "[]=", "MatrixRow", this, "Attempt to access null reference!")
            debug call ThrowError(column < 0 or column >= maxCols, "Matrices", "[]=", "MatrixRow", this, "Can't access Matrix! Column index "+I2S(column)+" exceeds Matrix dimensions!")
            set this.values[column] = value
        endmethod
        
        static method create takes integer cols returns thistype
            local thistype this = MatrixRow.allocate()
            set this.maxCols = cols
            return this
        endmethod
    endstruct

    private module Inits
        private static method onInit takes nothing returns nothing
            set Matrix.Invalid_Matrix = Matrix.createInvalid()
        endmethod
    endmodule
    
    private module GETTER_MODULE
        private integer _n
        private integer _m
        
        method operator n takes nothing returns integer
            debug call ThrowError(this == 0, "Matrices", "n", "Matrix", this, "Attempt to access null reference!")
            return _n
        endmethod
        method operator n= takes integer value returns nothing
            debug call ThrowError(this == 0, "Matrices", "n=", "Matrix", this, "Attempt to access null reference!")
            set _n = value
        endmethod
        
        method operator m takes nothing returns integer
            debug call ThrowError(this == 0, "Matrices", "m", "Matrix", this, "Attempt to access null reference!")
            return _m
        endmethod
        method operator m= takes integer value returns nothing
            debug call ThrowError(this == 0, "Matrices", "m=", "Matrix", this, "Attempt to access null reference!")
            set _m = value
        endmethod
    endmodule
    
    struct Matrix
        private MatrixRow array matRow[MAX_MATRIX_SIZE]
        
        static constant integer ONE_NORM = 1
        static constant integer EUCLIDEAN_NORM = 2
        static constant integer INFINITY_NORM = 3
        
        static constant integer METHOD_ROW_WISE = 0
        static constant integer METHOD_COL_WISE = 1
        
        readonly static Matrix Invalid_Matrix
        implement GETTER_MODULE

        method operator [] takes integer row returns MatrixRow
            debug call ThrowError(this == 0, "Matrices", "[]", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(row < 0 or row >= n, "Matrices", "[]", "Matrix", this, "Can't access Matrix! Row index "+I2S(row)+" exceeds Matrix dimensions!")
            return this.matRow[row]
        endmethod
        
        static method create takes integer nDim, integer mDim returns thistype
            local integer i = 0
            local thistype this 
            
            debug call ThrowError(nDim < 1, "Matrices", "create", "Matrix", 0, "Can't create Matrix with "+I2S(nDim)+" rows! Number of rows must be larger than zero!")
            debug call ThrowError(mDim < 1, "Matrices", "create", "Matrix", 0, "Can't create Matrix with "+I2S(mDim)+" columns! Number of columns must be larger than zero!")
            debug call ThrowError(nDim > MAX_MATRIX_SIZE, "Matrices", "create", "Matrix", 0, "Can't create Matrix with "+I2S(nDim)+" rows! Number of rows exceeds maximum row count of "+I2S(MAX_MATRIX_SIZE)+"!")
            debug call ThrowError(mDim > MAX_MATRIX_SIZE, "Matrices", "create", "Matrix", 0, "Can't create Matrix with "+I2S(mDim)+" columns! Number of columns exceeds maximum column count "+I2S(MAX_MATRIX_SIZE)+"!")
            
            set this = Matrix.allocate()
            loop
                exitwhen i > nDim - 1
                set this.matRow[i] = MatrixRow.create(mDim)
                set i = i + 1
            endloop
            set this.n = nDim
            set this.m = mDim
            
            return this
        endmethod
        
        private static method createInvalid takes nothing returns thistype
            local thistype this = Matrix.allocate()

            set this.n = 0
            set this.m = 0
            
            return this
        endmethod
        
        method isValid takes nothing returns boolean
            debug call ThrowError(this == 0, "Matrices", "isValid", "Matrix", this, "Attempt to access null reference!")
            return this.n == 0
        endmethod
        
        method isEqual takes Matrix mat returns boolean
            local integer i = 0
            local integer j = 0
        
            debug call ThrowError(this == 0, "Matrices", "isEqual", "Matrix", this, "Attempt to access null reference!")
        
            if this.n != mat.n or this.m != mat.m then
                return false
            endif
            
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    if this.matRow[i][j] != mat[i][j] then
                        return false
                    endif
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return true
        endmethod
        
        method addScalar takes real value returns Matrix
            local integer i = 0
            local integer j = 0
            local Matrix mat

            debug call ThrowError(this == 0, "Matrices", "addScalar", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "addScalar", "Matrix", this, "Cannot add "+R2S(value)+" to Matrix elements of and Invalid Matrix!")
            
            set mat = Matrix.create(n, m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set mat[i][j] = this.matRow[i][j] + value
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
        
        method subScalar takes real value returns Matrix
            local integer i = 0
            local integer j = 0
            local Matrix mat
            
            debug call ThrowError(this == 0, "Matrices", "subScalar", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "subScalar", "Matrix", this, "Cannot subtract "+R2S(value)+" to Matrix elements of and Invalid Matrix!")
            
            set mat = Matrix.create(n, m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set mat[i][j] = this.matRow[i][j] - value
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
        
        method multScalar takes real value returns Matrix
            local integer i = 0
            local integer j = 0
            local Matrix mat
            
            debug call ThrowError(this == 0, "Matrices", "multScalar", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "multScalar", "Matrix", this, "Cannot multiply "+R2S(value)+" to Matrix elements of and Invalid Matrix!")
            
            set mat = Matrix.create(n, m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set mat[i][j] = this.matRow[i][j]*value
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
        
        method divScalar takes real value returns Matrix
            local integer i = 0
            local integer j = 0
            local Matrix mat
            
            debug call ThrowError(this == 0, "Matrices", "divScalar", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "divScalar", "Matrix", this, "Cannot divide Matrix elements of Invalid Matrix by "+R2S(value)+"!")
            
            set mat = Matrix.create(n, m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set mat[i][j] = this.matRow[i][j]/value
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
        
        method abs takes nothing returns Matrix
            local integer i = 0
            local integer j = 0
            local Matrix mat
            
            debug call ThrowError(this == 0, "Matrices", "abs", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "abs", "Matrix", this, "Cannot perform absolute value to Matrix elements of and Invalid Matrix!")
            
            set mat = Matrix.create(n, m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    if this.matRow[i][j] >= 0 then
                        set mat[i][j] = this.matRow[i][j]
                    else
                        set mat[i][j] = -this.matRow[i][j]
                    endif
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
        
        method eye takes real value returns nothing
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "eye", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "eye", "Matrix", this, "Invalid Matrix!")
            
            loop
                exitwhen j >= n
                loop
                    exitwhen i >= m
                    if i != j then
                        set this.matRow[j][i] = 0.0
                    else
                        set this.matRow[j][i] = 1.0
                    endif
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
        endmethod
        
        method diag takes real value, integer whichDiagonal returns nothing
            local integer i = 0
            local integer j = 0
            local integer minDim
            
            debug call ThrowError(this == 0, "Matrices", "diag", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "diag", "Matrix", this, "Invalid Matrix!")
            
            if n <= m then
                set minDim = n - 1
            else
                set minDim = m - 1
            endif
            
            debug call ThrowError(whichDiagonal > minDim, "Matrices", "diag", "Matrix", this, "Diagonal Index "+I2S(whichDiagonal)+" exceeds Matrix dimensions!")
            
            loop
                exitwhen j >= n
                loop
                    exitwhen i >= m
                    if i != j - whichDiagonal then
                        set this.matRow[j][i] = 0.0
                    else
                        set this.matRow[j][i] = value
                    endif
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
        endmethod
        
        method init takes real value returns nothing
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "init", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "init", "Matrix", this, "Invalid Matrix!")
            
            loop
                exitwhen j >= n
                loop
                    exitwhen i >= m
                    set this.matRow[j][i] = value
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
        endmethod
        
        method rand takes real lowerBound, real upperBound returns nothing
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "rand", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "rand", "Matrix", this, "Invalid Matrix!")
            
            loop
                exitwhen j >= n
                loop
                    exitwhen i >= m
                    set this.matRow[j][i] = GetRandomReal(lowerBound, upperBound)
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
        endmethod
        
        method initStepWise takes real startValue, real step, integer whichMethod returns nothing
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "initStepWise", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "initStepWise", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(whichMethod != METHOD_ROW_WISE and whichMethod != METHOD_COL_WISE, "Matrices", "initStepWise", "Matrix", this, "Invalid method of number "+I2S(whichMethod)+" for initializing!")
            
            if whichMethod == METHOD_ROW_WISE then
                loop
                    exitwhen j >= n
                    loop
                        exitwhen i >= m
                        set this.matRow[j][i] = startValue
                        set startValue = startValue + step
                        set i = i + 1
                    endloop
                    set i = 0
                    set j = j + 1
                endloop
            elseif whichMethod == METHOD_COL_WISE then
                loop
                    exitwhen j >= m
                    loop
                        exitwhen i >= n
                        set this.matRow[i][j] = startValue
                        set startValue = startValue + step
                        set i = i + 1
                    endloop
                    set i = 0
                    set j = j + 1
                endloop
            endif
        endmethod
  
        method add takes Matrix mat returns Matrix
            local Matrix result
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "add", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "add", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(mat.n != this.n or mat.m != this.m, "Matrices", "add", "Matrix", this, "Cannot perform addition of a "+I2S(n)+" x "+I2S(m)+" with a "+I2S(mat.n)+" x "+I2S(mat.m)+" Matrix!")
            
            set result = Matrix.create(n, m)
            loop
                exitwhen j >= n
                loop
                    exitwhen i >= m
                    set result[j][i] = this.matRow[j][i] + mat[j][i]
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
            
            return result
        endmethod
        
        method sub takes Matrix mat returns Matrix
            local Matrix result
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "sub", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "sub", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(mat.n != this.n or mat.m != this.m, "Matrices", "sub", "Matrix", this, "Cannot perform subtraction of a "+I2S(n)+" x "+I2S(m)+" with a "+I2S(mat.n)+" x "+I2S(mat.m)+" Matrix!")
            
            set result = Matrix.create(n, m)
            loop
                exitwhen j >= n
                loop
                    exitwhen i >= m
                    set result[j][i] = this.matRow[j][i] - mat[j][i]
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
            
            return result
        endmethod
  
        method multiply takes Matrix mat returns Matrix
            local Matrix result
            local integer i = 0
            local integer j = 0
            local integer k = 0
            local real temp = 0.0
            
            debug call ThrowError(this == 0, "Matrices", "multiply", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "multiply", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(this.m != mat.n, "Matrices", "multiply", "Matrix", this, "Cannot perform multiplication of a "+I2S(n)+" x "+I2S(m)+" with a "+I2S(mat.n)+" x "+I2S(mat.m)+" Matrix!")
            
            set result = Matrix.create(n, mat.m)
            loop
                exitwhen j >= result.n
                loop
                    exitwhen k >= result.m
                    loop
                        exitwhen i >= this.m
                        set temp = temp + this.matRow[j][i]*mat[i][k]
                        set i = i + 1
                    endloop
                    set result[j][k] = temp
                    set i = 0
                    set temp = 0.0
                    set k = k + 1
                endloop
                set k = 0
                set j = j + 1
            endloop
            
            return result
        endmethod
  
        method transpose takes nothing returns Matrix
            local Matrix mat = Matrix.create(m, n)
            local integer i = 0
            local integer j = 0

            debug call ThrowError(this == 0, "Matrices", "transpose", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "transpose", "Matrix", this, "Invalid Matrix!")
            
            loop
                exitwhen j >= m
                loop
                    exitwhen i >= n
                    set mat[j][i] = this.matRow[i][j]
                    set i = i + 1
                endloop
                set i = 0
                set j = j + 1
            endloop
            
            return mat
        endmethod

        method gauss takes nothing returns Matrix
            local Matrix mat
            local integer i = 0
            local integer j = 0
            local integer k = 0
            local integer row
            local real maxVal = -Math.Inf
            local real pivot
            
            debug call ThrowError(this == 0, "Matrices", "gauss", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "gauss", "Matrix", this, "Invalid Matrix!")
            
            set mat = this.assign() 
            loop
                exitwhen i >= n - 1
                set j = i
                set row = i
                loop
                    exitwhen j >= m
                    set pivot = Math.abs(mat[j][i])
                    if pivot > maxVal then
                        set maxVal = pivot
                        set row = j
                    endif
                    set j = j + 1
                endloop
                
                if Math.abs(pivot) < EPSILON then
                    debug call ThrowWarning(true, "Matrices", "gauss", "Matrix", this, "Can't perform Gauss Elimination, Matrix too close to singularity!")
                endif 

                if row != i then
                    set j = 0
                    loop
                        exitwhen j >= m
                        set pivot = mat[i][j]
                        set mat[i][j] = mat[row][j]
                        set mat[row][j] = pivot
                        set j = j + 1
                    endloop
                endif

                if mat[i][i] >= EPSILON then
                    set j = i + 1
                    loop
                        exitwhen j >= n
                        set pivot = mat[j][i]/mat[i][i]
                        set k = i
                        loop
                            exitwhen k >= n
                            set mat[j][k] = mat[j][k] - pivot*mat[i][k]
                            set k = k + 1
                        endloop
                        set j = j + 1
                    endloop
                endif
                set i = i + 1
            endloop
        
            return mat
        endmethod
  
        method invert takes nothing returns Matrix
            local Matrix mat
            local Matrix inv
            local integer i = 0
            local integer j = 0
            local integer k = 0
            local integer row
            local real maxVal = -Math.Inf
            local real pivot
            local real temp_inv
            
            debug call ThrowError(this == 0, "Matrices", "invert", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "invert", "Matrix", this, "Invalid Matrix!")
            
            set mat = this.assign()
            set inv = Matrix.create(n, n)
            call inv.eye(n)
            loop
                exitwhen i >= n - 1
                set j = i + 1
                set row = i
                loop
                    exitwhen j >= n
                    set pivot = Math.abs(mat[j][i])
                    if pivot > maxVal then
                        set maxVal = pivot
                        set row = j
                    endif
                    set j = j + 1
                endloop
                
                if Math.abs(pivot) < EPSILON then
                    debug call ThrowWarning(true, "Matrices", "invert", "Matrix", this, "Can't invert Matrix, too close to singularity!")
                    return Matrix.Invalid_Matrix
                endif
                
                if row != i then
                    set j = 0
                    loop
                        exitwhen j >= m
                        set pivot = mat[i][j]
                        set mat[i][j] = mat[row][j]
                        set mat[row][j] = pivot
                        set temp_inv = inv[i][j]
                        set inv[i][j] = inv[row][j]
                        set inv[row][j] = temp_inv
                        set j = j + 1
                    endloop
                endif
                
                set j = i + 1
                loop
                    exitwhen j >= n
                    set pivot = mat[j][i]/mat[i][i]
                    set k = 0
                    loop
                        exitwhen k >= n
                        set mat[j][k] = mat[j][k] - pivot*mat[i][k]
                        set inv[j][k] = inv[j][k] - pivot*inv[i][k]
                        set k = k + 1
                    endloop
                    set j = j + 1
                endloop
                set i = i + 1
            endloop
            
            set i = n - 1
            loop
                exitwhen i < 0
                set j = i - 1
                loop
                    exitwhen j < 0
                    set pivot = mat[j][i]/mat[i][i]
                    set mat[j][i] = mat[j][i] - pivot*mat[i][i]
                    set k = 0
                    loop
                        exitwhen k >= m
                        set inv[j][k] = inv[j][k] - pivot*inv[i][k]
                        set k = k + 1
                    endloop
                    set j = j - 1
                endloop
                set i = i - 1
            endloop
            
            set i = 0
            loop
                exitwhen i >= n
                set j = 0
                loop
                    exitwhen j >= m
                    set inv[i][j] = inv[i][j]/mat[i][i]
                    set j = j + 1
                endloop
                set i = i + 1
            endloop
            call mat.destroy()
            
            return inv
        endmethod
  
        method trace takes nothing returns real
            local integer i = 0
            local integer minDim
            local real result = 0.0
            
            debug call ThrowError(this == 0, "Matrices", "trace", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "trace", "Matrix", this, "Invalid Matrix!")
            
            if n <= m then
                set minDim = n - 1
            else
                set minDim = m - 1
            endif
            
            loop
                exitwhen i > minDim
                set result = result + this.matRow[i][i]
                set i = i + 1
            endloop
        
            return result
        endmethod
        
        method assign takes nothing returns Matrix
            local integer i = 0
            local integer j = 0
            local Matrix mat = Matrix.create(n, m)
            
            debug call ThrowError(this == 0, "Matrices", "assign", "Matrix", this, "Attempt to access null reference!")
   
            if n < 1 then
                set mat = Invalid_Matrix
                return mat
            endif
            
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set mat[i][j] = this.matRow[i][j]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
        
        method rank takes nothing returns integer
            local Matrix mat = this.assign()
            local integer minDim
            local integer i
            local integer rank
            
            debug call ThrowError(this == 0, "Matrices", "rank", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "rank", "Matrix", this, "Invalid Matrix!")
            
            if n <= m then
                set minDim = n - 1
            else
                set minDim = m - 1
            endif
            
            set i = minDim
            set rank = minDim + 1
            set mat = this.gauss()
            
            loop
                exitwhen i < 1
                if Math.abs(mat[i][i]) < EPSILON then
                    set rank = rank - 1
                endif
                set i = i - 1
            endloop
            
            return rank
        endmethod
        
        method cond takes integer whichNorm returns real
            local Matrix mat
            local real result

            debug call ThrowError(this == 0, "Matrices", "cond", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "cond", "Matrix", this, "Invalid Matrix!")
            
            set mat = this.assign()
            set mat = mat.invert()
            
            if not mat.isValid() then
                debug call ThrowError(true, "Matrices", "cond", "Matrix", this, "Matrix has infinite condition!")
                return Math.Inf
            endif
            
            set mat = this.multiply(mat)
            set result = mat.norm(whichNorm)
            call mat.destroy()
            return result
        endmethod
        
        method det takes nothing returns real
            local Matrix mat
            local integer i = 0
            local real result = 1.0
            
            debug call ThrowError(this == 0, "Matrices", "det", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "det", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(n != m, "Matrices", "det", "Matrix", this, "Matrix "+I2S(n)+" x "+I2S(m)+" isn't square! Matrix must be square!")
            
            set mat = this.assign()
            set mat = mat.gauss()
            
            loop
                exitwhen i >= n
                set result = result*mat[i][i]
                set i = i + 1
            endloop
            if Math.abs(result) < EPSILON then
                set result = 0.0
            endif
            
            call mat.destroy()
            return result
        endmethod
    
        method solveSLE takes Matrix b returns Matrix
            local Matrix mat
            local Matrix sol
            local Matrix x
            local integer i = 0
            local integer j = 0
            local integer k = 0
            local integer row
            local real maxVal = -Math.Inf
            local real pivot
            
            debug call ThrowError(this == 0, "Matrices", "solveSLE", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "solveSLE", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(this.n != this.m or b.n != this.n or b.m > 1, "Matrices", "solveSLE", "Matrix", this, "Invalid Matrices used! Can't solve SLE!")
            
            set mat = this.assign()
            set sol = b.assign()
            set x = Matrix.create(b.n, 1)
            loop
                exitwhen i >= n - 1
                set j = i + 1
                set row = i
                loop
                    exitwhen j >= n
                    set pivot = Math.abs(mat[j][i])
                    if pivot > maxVal then
                        set maxVal = pivot
                        set row = j
                    endif
                    set j = j + 1
                endloop
                set pivot = maxVal
                
                if Math.abs(pivot) < EPSILON then
                    return Matrix.Invalid_Matrix
                endif
                
                if row != i then
                    set j = 0
                    loop
                        exitwhen j >= m
                        set pivot = mat[i][j]
                        set mat[i][j] = mat[row][j]
                        set mat[row][j] = pivot
                        set j = j + 1
                    endloop
                    set pivot = sol[i][0]
                    set sol[i][0] = sol[row][0]
                    set sol[row][0] = pivot
                endif
                
                set j = i + 1
                loop
                    exitwhen j >= n
                    set pivot = mat[j][i]/mat[i][i]
                    set k = i
                    loop
                        exitwhen k >= n
                        set mat[j][k] = mat[j][k] - pivot*mat[i][k]
                        set k = k + 1
                    endloop
                    set sol[j][0] = sol[j][0] - pivot*sol[i][0]
                    set j = j + 1
                endloop
                set i = i + 1
            endloop
            
            set x[x.n - 1][0] = sol[x.n - 1][0]/mat[n - 1][n - 1]
            set i = x.n - 2
            loop
                exitwhen i < 0
                set pivot = sol[i][0]
                set j = i + 1
                loop
                    exitwhen j >= n
                    set pivot = pivot - mat[i][j]*x[j][0]
                    set j = j + 1
                endloop
                set x[i][0] = pivot/mat[i][i]
                set i = i - 1
            endloop
            call sol.destroy()
            call mat.destroy()
            
            return x
        endmethod
  
        method norm takes integer whichNorm returns real
            local integer i = 0
            local integer j = 0
            local real result
            local real maxVal = -Math.Inf
            
            debug call ThrowError(this == 0, "Matrices", "norm", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "norm", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(whichNorm != ONE_NORM and whichNorm != EUCLIDEAN_NORM and whichNorm != INFINITY_NORM, "Matrices", "[]", "Matrix", this, "Invalid Norm with number "+I2S(whichNorm)+" used!")
            
            if whichNorm == ONE_NORM then
                set result = 0.0
                loop
                    exitwhen i >= m
                    loop
                        exitwhen j >= n
                        set result = result + Math.abs(this.matRow[j][i])
                        set j = j + 1
                    endloop
                    if result > maxVal then
                        set maxVal = result
                    endif
                    set result = 0.0
                    set j = 0
                    set i = i + 1
                endloop
                return maxVal
            elseif whichNorm == EUCLIDEAN_NORM then
                set result = 0.0
                loop
                    exitwhen i >= n
                    loop
                        exitwhen j >= m
                        set result = result + this.matRow[i][j]*this.matRow[i][j]
                        set j = j + 1
                    endloop
                    set j = 0
                    set i = i + 1
                endloop
                return SquareRoot(result)
            else
                set result = 0.0
                loop
                    exitwhen i >= n
                    loop
                        exitwhen j >= m
                        set result = result + Math.abs(this.matRow[i][j])
                        set j = j + 1
                    endloop
                    if result > maxVal then
                        set maxVal = result
                    endif
                    set result = 0.0
                    set j = 0
                    set i = i + 1
                endloop
                return maxVal
            endif
        endmethod
  
        method kron takes Matrix mat returns Matrix
            local Matrix result = Matrix.create(n*mat.n, m*mat.m)
            local integer i = 0
            local integer j = 0
            local integer k = 0
            local integer l = 0
            
            debug call ThrowError(this == 0, "Matrices", "kron", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1 or mat.n < 1, "Matrices", "kron", "Matrix", this, "Can't compute Kronecker Product of Invalid Matrix!")
            
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= mat.n
                    loop
                        exitwhen k >= m
                        loop
                            exitwhen l >= mat.m
                            set result[i*n + k][j*m + l] = this.matRow[i][j]*mat[k][l]
                            set l = l + 1
                        endloop
                        set l = 0
                        set k = k + 1
                    endloop
                    set k = 0
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return result
        endmethod
  
        method dotProduct takes Matrix mat returns real
            local real temp = 0.0
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "dotProduct", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1 or mat.n < 1, "Matrices", "dotProduct", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(mat.m != 1 or this.m != 1, "Matrices", "dotProduct", "Matrix", this, "Dot-Product is only defined for Vectors!")
            debug call ThrowError(mat.n != this.n, "Matrices", "dotProduct", "Matrix", this, "Dot-Product is only defined for Vectors of same length!")
            
            loop
                exitwhen i > n
                set temp = temp + this.matRow[i][1]*mat[i][1]
                set i = i + 1
            endloop
            
            return temp
        endmethod
  
        method crossProduct takes Matrix mat returns Matrix
            local Matrix result
        
            debug call ThrowError(this == 0, "Matrices", "crossProduct", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1 or mat.n < 1, "Matrices", "crossProduct", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(mat.m != 1 or this.m != 1, "Matrices", "crossProduct", "Matrix", this, "Cross-Product is only defined for Vectors!")
            debug call ThrowError(mat.n != this.n, "Matrices", "crossProduct", "Matrix", this, "Cross-Product is only defined for Vectors of same length!")
            debug call ThrowError(mat.n != 3 or this.n != 3, "Matrices", "crossProduct", "Matrix", this, "This implementation only supports Cross-Products for Vectors in R^3")
            
            set result = Matrix.create(3, 1)
            set result[0][0] = this.matRow[1][0]*mat[2][0] - this.matRow[2][0]*mat[1][0]
            set result[1][0] = this.matRow[2][0]*mat[0][0] - this.matRow[0][0]*mat[2][0]
            set result[2][0] = this.matRow[0][0]*mat[1][0] - this.matRow[1][0]*mat[0][0]
            
            return result
        endmethod
  
        method reShape takes integer newN, integer newM, integer whichMethod returns Matrix
            local Matrix mat
            local integer i = 0
            local integer j = 0
            local integer row = 0
            local integer col = 0
            
            debug call ThrowError(this == 0, "Matrices", "reShape", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "reShape", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(newN*newM != n*m, "Matrices", "reShape", "Matrix", this, "Can't reshape a "+I2S(n)+" x "+I2S(m)+" Matrix to a "+I2S(newN)+" x "+I2S(newM)+" Matrix! Dimension missmatch!")
            debug call ThrowError(newN < 1 or newM < 1, "Matrices", "reShape", "Matrix", this, "Reshape not possible! Index must be greater than zero!")
            debug call ThrowError(whichMethod != METHOD_ROW_WISE and whichMethod != METHOD_COL_WISE, "Matrices", "reShape", "Matrix", this, "Invalid method with number "+I2S(whichMethod)+" for reshaping!")
            
            set mat = Matrix.create(newN, newM)
            
            if whichMethod == METHOD_ROW_WISE then
                loop
                    exitwhen i >= n
                    loop
                        exitwhen j >= m
                        set mat[row][col] = this.matRow[i][j]
                        set col = col + 1
                        if col >= mat.m then
                            set row = row + 1
                            set col = 0
                        endif
                        set j = j + 1
                    endloop
                    set j = 0
                    set i = i + 1
                endloop
            elseif whichMethod == METHOD_COL_WISE then
                loop
                    exitwhen i >= m
                    loop
                        exitwhen j >= n
                        set mat[row][col] = this.matRow[j][i]
                        set col = col + 1
                        if col >= mat.m then
                            set row = row + 1
                            set col = 0
                        endif
                        set j = j + 1
                    endloop
                    set j = 0
                    set i = i + 1
                endloop
            endif
            
            return mat
        endmethod
  
        method embed takes Matrix subMat, integer startRow, integer startCol returns Matrix
            local Matrix mat
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "embed", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n == 0 or subMat.n == 0, "Matrices", "embed", "Matrix", this, "Can't embed sub Matrix! This is an invalid Matrix!")
            debug call ThrowError(startRow < 0 or startCol < 0, "Matrices", "embed", "Matrix", this, "Can't merge Matrices to start row "+I2S(startRow)+" and start column "+I2S(startCol)+"! Index must be greater than 0!")
            debug call ThrowError(startRow + subMat.n - 1 > n or startCol + subMat.m - 1 > m, "Matrices", "embed", "Matrix", this, "Can't merge Matrices to start row "+I2S(startRow)+" and start column "+I2S(startCol)+"! Matrices don't fit!")
            
            set mat = this.assign()
            loop
                exitwhen i >= subMat.n
                loop
                    exitwhen j >= subMat.m
                    set mat[i + startRow][j + startCol] = subMat[i][j]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
  
        method subMatrix takes integer startRow, integer startCol, integer endRow, integer endCol returns Matrix
            local Matrix mat
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "subMatrix", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n == 0, "Matrices", "subMatrix", "Matrix", this, "Can't determine sub Matrix! This is an invalid Matrix!")
            debug call ThrowError(endRow < startRow or endCol < startCol, "Matrices", "subMatrix", "Matrix", this, "Can't determine sub Matrix! Size of sub Matrix smaller 1 x 1!")
            debug call ThrowError(endRow > n - 1 or endCol > m - 1, "Matrices", "subMatrix", "Matrix", this, "Sub Matrix of size "+I2S(endRow - startRow + 1)+" x "+I2S(endCol - startCol + 1)+" exceeds Matrix dimensions!")
            
            set mat = Matrix.create(endRow - startRow + 1, endCol - startCol + 1)
            loop
                exitwhen i >= mat.n
                loop
                    exitwhen j >= mat.m
                    set mat[i][j] = this.matRow[i + startRow][j + startCol]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return mat
        endmethod
    
        method concatV takes Matrix mat returns Matrix
            local Matrix result
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "concatV", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n == 0 or m == 0, "Matrices", "concatV", "Matrix", this, "Can't concat Invalid Matrices!")
            debug call ThrowError(m != mat.m, "Matrices", "concatV", "Matrix", this, "Can't concat Matrices! Matrix column dimensions must be equal!")
    
            set result = Matrix.create(n + mat.n, m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set result[i][j] = mat[i][j]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            set i = 0
            set j = 0
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set result[i + n][j] = this.matRow[i][j]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            
            return result
        endmethod
    
        method concatH takes Matrix mat returns Matrix
            local Matrix result
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "concatH", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n == 0 or m == 0, "Matrices", "concatH", "Matrix", this, "Can't concat Invalid Matrices!")
            debug call ThrowError(n != mat.n, "Matrices", "concatH", "Matrix", this, "Can't concat Matrices! Matrix row dimensions must be equal!")
            
            set result = Matrix.create(n, m + mat.m)
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set result[i][j] = this.matRow[i][j]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop
            set i = 0
            set j = 0
            loop
                exitwhen i >= n
                loop
                    exitwhen j >= m
                    set result[i][j + m] = mat[i][j]
                    set j = j + 1
                endloop
                set j = 0
                set i = i + 1
            endloop

            return result
        endmethod
  
        method switchRow takes integer whichRow, integer newRow returns nothing
            local real temp
            local integer i = 0
            
            debug call ThrowError(this == 0, "Matrices", "switchRow", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "switchRow", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(whichRow < 0 or whichRow >= n or newRow < 0 or newRow >= n, "Matrices", "switchRow", "Matrix", this, "Can't switch row "+I2S(whichRow)+" with "+I2S(newRow)+". Index exceeds Matrix dimensions!")
            
            loop
                exitwhen i >= this.m
                set temp = this.matRow[newRow][i]
                set this.matRow[newRow][i] = this.matRow[whichRow][i]
                set this.matRow[whichRow][i] = temp
                set i = i + 1
            endloop
        endmethod
  
        method switchCol takes integer whichCol, integer newCol returns nothing
            local real temp
            local integer i = 0
            
            debug call ThrowError(this == 0, "Matrices", "switchCol", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowError(n < 1, "Matrices", "switchCol", "Matrix", this, "Invalid Matrix!")
            debug call ThrowError(whichCol < 0 or whichCol >= n or newCol < 0 or newCol >= n, "Matrices", "switchCol", "Matrix", this, "Can't switch column "+I2S(whichCol)+" with "+I2S(newCol)+". Index exceeds Matrix dimensions!")
            
            loop
                exitwhen i >= this.n
                set temp = this.matRow[i][newCol]
                set this.matRow[i][newCol] = this.matRow[i][whichCol]
                set this.matRow[i][whichCol] = temp
                set i = i + 1
            endloop
        endmethod
  
        method display takes nothing returns nothing
            local string s = ""
            local integer i = 0
            local integer j = 0
            
            debug call ThrowError(this == 0, "Matrices", "display", "Matrix", this, "Attempt to access null reference!")
            debug call ThrowWarning(n < 1, "Matrices", "display", "Matrix", this, "Invalid Matrix can't be displayed!")
            
            loop
                exitwhen j >= this.n
                loop
                    exitwhen i >= this.m
                    set s = s + " " + R2S(this.matRow[j][i])
                    set i = i + 1
                endloop
                call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 60.0, s)
                set s = ""
                set i = 0
                set j = j + 1
            endloop
        endmethod
        
        implement Inits
    endstruct
endlibrary

And here a little example that demonstrates the solution of a System of Linear Equations (SLE).

JASS:
scope Example initializer Init
    private function Init takes nothing returns nothing
        /**********************************************************************************
        *
        *   Example Code
        *   ¯¯¯¯¯¯¯¯¯¯¯¯
        *
        *   Solves the Linear System of Equations A*x = b for 
        *
        *    [1][4][7]   [x1]   [1]                          [ 0]
        *   [17][5][8] * [x2] = [2]    with the solution x = [ 2] approximately.
        *    [3][6][9]   [x3]   [3]                          [-1]
        *
        *   Feel free to try out more.
        *
        **********************************************************************************/
    
        // Create a 3 x 3 system Matrix A
        local Matrix A = Matrix.create(3, 3)
        
        // Create a 3 x 1 solution Vector b
        local Matrix b = Matrix.create(3, 1)
        
        // Instanciate the unknown Vector x
        local Matrix x

        // Initialize Matrix A in ascending order (col-wise)
        call A.initStepWise(1.0, 1.0, Matrix.METHOD_COL_WISE)
        
        // Set the element in the second row, first column of A to 17.0
        set A[1][0] = 17.0
        
        // Initialize Vector b (row-wise)
        call b.initStepWise(1.0, 1.0, Matrix.METHOD_ROW_WISE)
        
        // Solve SLE
        set x = A.solveSLE(b)

        // Display A, b and x
        call A.display()
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 60.0, " ")
        call b.display()
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0.0, 0.0, 60.0, " ")
        call x.display()
    endfunction
endscope

Even more detailed documentation will be included as a sub-chapter to the Math library soon.
 

Attachments

  • Matrices.w3x
    60.2 KB · Views: 191
Last edited:
I'm going to have to look through this.

I recommend ErrorMessage over your own custom errors.

Also keep in mind that plain vJASS structs do generate some extra garbage code.

I don't see dot or cross product and it's missing magnitude. Getting a unit vector from a vector would also be helpful.

You also do know that this will do lots of multiplication and addition whenever you read an element right?

real array values[MAX_MATRIX_SIZE]

All error checking should be debug only as well. I know if I'm doing AES, I want to minimize the operation count to minimize how much the thing freezes during encrypting/decrypting. Every little operation counts and can make a pretty big difference ;o.

edit
Please also create a testing suite to ensure that this is absolutely bugless =). Yea, I know right now everything's chaotic, but trying to bring in some order. You'll notice that I wrote a collections testing suite ^)^.

What I can say is that you have gotten much better at coding. You have advanced leaps and bounds from your physical damage detection. Very good ; ). I expect great things from you in the future.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
I don't see dot or cross product and it's missing magnitude. Getting a unit vector from a vector would also be helpful.

Right, I will add those. If I missed more functions, please tell me.

You also do know that this will do lots of multiplication and addition whenever you read an element right?

When I read an element? You mean local real r = mat[1][2] will cause additions and multiplications? How's that?

All error checking should be debug only as well. I know if I'm doing AES, I want to minimize the operation count to minimize how much the thing freezes during encrypting/decrypting. Every little operation counts and can make a pretty big difference ;o.


edit
Please also create a testing suite to ensure that this is absolutely bugless =). Yea, I know right now everything's chaotic, but trying to bring in some order. You'll notice that I wrote a collections testing suite ^)^.

Will do.

What I can say is that you have gotten much better at coding. You have advanced leaps and bounds from your physical damage detection. Very good ; ). I expect great things from you in the future.

Thanks :)


EDIT:
Magnitute is already there, the euclidean norm returns a vectors magnitude, for a Matrix its the frobenius norm.
 
Last edited:
Level 14
Joined
Dec 12, 2012
Messages
1,007
local real r = mat[1][2]

is

local real r = mat[1*n + 2]

Oh, I see.

Because you are reading from a constant row, it could just be

row = whatever

local real r = mat[row + index]

or you could iterate over elements of the row


Hm I don't understand... So it is possible to avoid these extra calculations?


EDIT:
Oh I see, if one access to a constant index... Well that doesn't help much unfortunatly because all functions use variant indices...
And for manual setting I think the API set mat[1][2] = someValue is the best.
 
Last edited:
Btw, why are you using your Math lib in this?

There is an Abs BJ function :\, and I don't see using the library for a constant.

edit
I don't really agree with a lot of the stuff in your Math lib. For example, you can check if something is an integer with R2I(number) == number. You do if statements and weird stuff for rounding instead.

It has string parsing... which really doesn't belong in a math lib, lol.

You redo things like RAbsBJ.


I just don't agree with a lot of stuff in your Math lib. I'm pretty averse to anything that uses it.

If it had been submitted to the JASS Section, I don't think that it would have been approved. As this uses such a resource, you should probably just submit this to the Spells section ;). You'd be better off then, the Spells section is way less strict. When a moderator doesn't think that the resource is particularly good, it'll get a low rating, but still be approved.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Update v 1.1.0.0
- Error Statements are now debug only
- initStepWise can now also be used column-wise
- New methods included:
- isEqual, checks for equality of two matrices
- dotProduct
- crossProduct
- subMatrix, gets a sub matrix out a matrix
- embed, embeds a matrix into another
- concatH, concatenates two matrices horizontaly
- concatV, concatenates two matrices vertically
- reShape, changes a matrix dimensions

Someone beat me :(
I thought my implementation of LuaMatrix to vJASS be better :(

You make something like that already? Where?

Btw, why are you using your Math lib in this?

There is an Abs BJ function :\, and I don't see using the library for a constant.

Well, but that constant requires an additional Pow call, so why should I do that in every resource that requires that constant if I can just have one collection with them all inside?

After the Matrices library I'm going to do more math stuff. Actually I need at the moment some CurveFitting and Optimization Stuff. Each of these libraries will require various things of the Math lib. User defined constants are also more accurate than the native ones, so it does make sense to collect them all together to rely on one basic framework.

That the Math library itself is not perfect is another thing, I can still remove the redundant functions. I asked back then what the mods think about but they didn't say anything so I thought its fine.

But that suggestion is just useless and arrogant:

If it had been submitted to the JASS Section, I don't think that it would have been approved. As this uses such a resource, you should probably just submit this to the Spells section ;). You'd be better off then, the Spells section is way less strict. When a moderator doesn't think that the resource is particularly good, it'll get a low rating, but still be approved.

Because the resource is good. There isn't really any much better way to implement matrices to Wc3 so, wouldn't it make much more sense to base future resources that are in need of matrices on such a resource?
 
Use ErrorMessage so that you get normal behavior and standard output. Your error messages are missing a lot of information.

1. You need to say the library name (good)
2. You need to say the object name (not so good)
3. You need to say the instance (not good)
4. You need to output all arguments (def not good)
5. You need to disable the system so that errors don't propagate (not so good)
6. You need to stop the thread so that errors don't propagate (not so good)

You are only meeting the first requirement. Put in the other 5.

Because the resource is good. There isn't really any much better way to implement matrices to Wc3 so, wouldn't it make much more sense to base future resources that are in need of matrices on such a resource?

Take out all of the string stuff from Math.

I want to know how your abs method is better than the RABsBJ/IAbsBJ functions.

If you improve the math lib, then I have no problems using it for constants, but right now it's filled with extraneous clutter ; ).

edit
Missing augment matrix
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Use ErrorMessage so that you get normal behavior and standard output. Your error messages are missing a lot of information.

1. You need to say the library name (good)
2. You need to say the object name (not so good)
3. You need to say the instance (not good)
4. You need to output all arguments (def not good)
5. You need to disable the system so that errors don't propagate (not so good)
6. You need to stop the thread so that errors don't propagate (not so good)

You are only meeting the first requirement. Put in the other 5.

Hm Ok, I will do that with the next update.

Take out all of the string stuff from Math.

Well I can make it an extension, just like Matrices. Not implementing it to Math but make it use its own struct. It basically only changes the API a bit, so I have no problem with doing so.

I want to know how your abs method is better than the RABsBJ/IAbsBJ functions.

It looks nicer, nothing more. Red functions are ugly, don't you think? :)

If you improve the math lib, then I have no problems using it for constants, but right now it's filled with extraneous clutter ; ).

K, I will remove all the trigonometry wrappers and exclude the string stuff. But rounding functions etc are useful as well as Ln, gamma or hyperbolics.

edit
Missing augment matrix

set A = A.concatH(B)
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Use ErrorMessage so that you get normal behavior and standard output. Your error messages are missing a lot of information.
...
If you improve the math lib, then I have no problems using it for constants, but right now it's filled with extraneous clutter ; ).

Done.


Update to Version 1.2.0.0
- Now using ErrorMessage
- Fixed some minor bugs
- Reworked the Maths library (see changelog here), removed redundant functions as well as the String Parsing.
 
Your still missing the arguments

debug call ThrowError(true, "Matrices", "[]", "Matrix", this, "Can't access Matrix! Index exceeds Matrix dimensions!")

The [] takes an argument row, yet you're not displaying it.

Example
JASS:
method enqueue takes thistype node returns nothing
            debug call ThrowError(this == 0,            "UniqueQueue", "enqueue", "thistype", this, "Attempted To Enqueue (" + I2S(node) + ") On To Null Queue.")
            debug call ThrowError(recycler[this] != -1, "UniqueQueue", "enqueue", "thistype", this, "Attempted To Enqueue (" + I2S(node) + ") On To Invalid Queue.")
            debug call ThrowError(node == 0,            "UniqueQueue", "enqueue", "thistype", this, "Attempted To Enqueue Null Node.")
            debug call ThrowError(node.isNode,          "UniqueQueue", "enqueue", "thistype", this, "Attempted To Enqueue Owned Node (" + I2S(node) + ").")

edit
Also put your expressions inside of the function call ;p

JASS:
            debug if  then
                debug call ThrowError(true, "Matrices", "[]=", "MatrixRow", this, "Can't access Matrix! Index exceeds Matrix dimensions!")
            debug endif

To

debug call ThrowError(column < 0 or column >= maxCols, "Matrices", "[]=", "MatrixRow", this, "Attempt To Set Out Of Bounds Matrix Column (" + I2S(column) + ").")

Always be very explicit with your errors. If [] takes a row, don't go with a generic index, state a row ;).

Also, it doesn't necessarily exceed the matrix because it may be < 0, it's really out of bounds.

edit
Under standard 4, public fields aren't allowed ;p

JASS:
        readonly static Matrix Invalid_Matrix
        
        readonly integer n
        readonly integer m

Those should be private with method operators, that way you can do error checking. Field names should be _n and _m. For now, put your struct inside of a module and implement that module into the struct, that way you can use this. Wait until a new jass parser comes out to get around the lame _n,_m syntax errors outside of a module.

edit
Put this below library reqs and above API listing please. It's hidden away down there.

JASS:
    globals
        /*************************************************************************
        *   Configurable globals
        *************************************************************************/
    
        // Accuracy for considering a Matrix too close to singularity
        private constant real EPSILON = 0.01 
    
        // Do you want the system to display debug error messages?
        private constant boolean DISPLAY_MATRIX_ERRORS = true
    
        // Biggest possible n x n-Matrix
        private constant integer MAX_MATRIX_SIZE = 50
        
        /*************************************************************************
        *   End of configurable globals
        *************************************************************************/
    endglobals

edit
While I know what m,n stand for because they are standard dimensions for a matrix, other people may not. You might want to change them to rows/columns. I know ur being cool with the math lingo, but still ;p.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Your still missing the arguments

debug call ThrowError(true, "Matrices", "[]", "Matrix", this, "Can't access Matrix! Index exceeds Matrix dimensions!")


edit
Also put your expressions inside of the function call ;p

Hm kk. Though this will be quite a lot of work -.-


edit
Under standard 4, public fields aren't allowed ;p

JASS:
        readonly static Matrix Invalid_Matrix
        
        readonly integer n
        readonly integer m

Whats wrong with public fields?


Those should be private with method operators, that way you can do error checking. Field names should be _n and _m. For now, put your struct inside of a module and implement that module into the struct, that way you can use this. Wait until a new jass parser comes out to get around the lame _n,_m syntax errors outside of a module.

What kind of error checking? They are readonly so you can't make anything wrong with them.

Also I don't think it makes sense to build (and enforce) a new standard with features that are (not yet) supported by jasshelper and very likely will never be.
Who should make such an update and when?

Also Matrix._n looks super stupid, don't you think?
 
Also I don't think it makes sense to build (and enforce) a new standard with features that are (not yet) supported by jasshelper and very likely will never be.
Who should make such an update and when?

I'm working on it right now : P

The user wouldn't use matrix._n, they would use matrix.n

Let's consider that a user uses 0 as a matrix by an error, or they accidentally use a deallocated matrix. If they did matrix.n and n was just a field, the error wouldn't be caught. If you made it a method operator, you could then check for errors, making sure that the matrix is both not null and not invalid.

JASS:
private integer _n
method operator n takes nothing returns integer
    debug call ThrowError(this == 0, ...)
    debug call ThrowError(this.isAllocated, ...)

    return _n
endmethod

This way you catch any errors as they occur. If you don't catch the error and then another error happens later, the user won't know where it originated from (the first occurance of the error). You should check for errors in everything that the user can interact with in your resource =).

You can also name it n_p or w/e if you'd prefer not to use the module workaround to get _n working.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
The user wouldn't use matrix._n, they would use matrix.n

Let's consider that a user uses 0 as a matrix by an error, or they accidentally use a deallocated matrix. If they did matrix.n and n was just a field, the error wouldn't be caught. If you made it a method operator, you could then check for errors, making sure that the matrix is both not null and not invalid.

Ok convinced, that makes sense.

I'm working on it right now : P

Really? Will you implement more stuff or only fix this Bug? Because I have a wish list here :D
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
This way you catch any errors as they occur. If you don't catch the error and then another error happens later, the user won't know where it originated from (the first occurance of the error). You should check for errors in everything that the user can interact with in your resource =).

You can also name it n_p or w/e if you'd prefer not to use the module workaround to get _n working.

Hm, I still have doubts about this practise to replace all fields with operators. While a field is just a variable (read out very fast) a method operator gets compiled into a function call which is much slower.

If I change for example the fields n and m to getter operators, performance drops by ~9% for gaussian elimination which is quite a lot. Especially when you consider that this is just for catching the case where a user uses a deallocated object I don't think its worth the performance lose as this is a really trivial error.
 
Hm, I still have doubts about this practise to replace all fields with operators. While a field is just a variable (read out very fast) a method operator gets compiled into a function call which is much slower.

If I change for example the fields n and m to getter operators, performance drops by ~9% for gaussian elimination which is quite a lot. Especially when you consider that this is just for catching the case where a user uses a deallocated object I don't think its worth the performance lose as this is a really trivial error.

It gets inlined out of debug mode
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
I tihnk you should add support for sparse matrices. This could be done by using triples of (row, col, value):
Code:
[ 15  7  0  0  0 ]
[  0  8 34  0  0 ]
[  0  0 57  0  0 ]
[  0  0  0 81  0 ]
[  0  0  0 10  0 ]

== ((1, 1, 15), (1, 2, 7), (2, 2, 8), (2, 3, 34), (3, 3, 57), (4, 4, 81), (5, 4, 10))

A similar approach is the yale sparse matrix format.


Anyway il have to agree with Adiktuz, nobody really uses this stuff in wc3...
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Well, that would be a seperate resource.

But the application of those data storage formats are large Matrices (really large ones), like 100000 x 100000 where its a problem to store those in the RAM of a common PC.

As you can't come even close to such huge Matrices anyway, it doesn't really make sense to implement something like this IMO. But you can of course make such a library and use this one as a base if you want ;)
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,258
Does this contain element wise matrix operations such as the ".*" from matlab? This operation uses standard mathematical multiplication between each element of the two matrices to produce a new matrix. It is similar to scalar multiplication except to do that using this operation you need a matrix consisting of the same size and all elements being the scalar.

Its main purpose is for mask matrices.
 
Level 6
Joined
Aug 26, 2009
Messages
192
Does this contain element wise matrix operations such as the ".*" from matlab? This operation uses standard mathematical multiplication between each element of the two matrices to produce a new matrix. It is similar to scalar multiplication except to do that using this operation you need a matrix consisting of the same size and all elements being the scalar.

You could also add an exponentiation and component-wise function-application like sine/cosine/...

Second:
How do you calculate the condition? If i see the code correctly you do it like
|A * A^-1| which is for submultiplicative norms always 1. It should actually be |A| * |A^-1|.
For gauss-algorithm. Didn't look into the code, but i hope you use at least pivoting. You could also give the posibility to obtain a LU-Decomposition in case someone wants to solve several linear equation with the same matrix.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
You could also add an exponentiation and component-wise function-application like sine/cosine/...

No I won't do that because you could always extend the list further making this basically what is called a monolith and this library is already big enough. If the user wants to do that he can easily iterate on his own over the Matrix and apply the function call on each element.

Second:
How do you calculate the condition? If i see the code correctly you do it like
|A * A^-1| which is for submultiplicative norms always 1. It should actually be |A| * |A^-1|.

Yes thats right, will fix.

For gauss-algorithm. Didn't look into the code, but i hope you use at least pivoting.

Well, if you didn't look at the code its quite to useless to discuss things like this. But yes, it is using pivoting. The variable used there is even called "pivot" -.-
 
Level 6
Joined
Aug 26, 2009
Messages
192
No I won't do that because you could always extend the list further making this basically what is called a monolith and this library is already big enough. If the user wants to do that he can easily iterate on his own over the Matrix and apply the function call on each element.

It wasn't actually meant like this, since DSG wanted you to implement something like this. That's why i quoted him.

Edit: In matlab this has actually a use since it can parallelise all this stuff. In wc3 it doesn't.
 
Last edited:
Level 14
Joined
Dec 12, 2012
Messages
1,007
How about adding a negate function which returns the additive inverse of a matrix.

No, as already stated a user can perform such things by simply iterating over the matrix himself. A library doesn't get better by just adding more and more functions to it. I could also add sin, cos, tan, exp, sqrt and so on and so on. But that would just add aditional overhead to the library.

Actually I'm thinking of removing some methods as the library is already very big.

And I'd recommend doing the swaps in gauss only implicit. Explicitly swapping all values is useless overhead imo.

Sorry, but what are you talking about?

Of course I only swap the required values and not all, lol. The algorithm for performing gaussian elimination is standardized and this is a typical implementation of it.
 
Level 6
Joined
Aug 26, 2009
Messages
192
Sorry, but what are you talking about?

When pivoting, you swap rows. If you take an array which holds the rownumbers as a wrapper, you don't have to actually swap the numbers, instead you just have one more array lookup. So the int array first looks like this:

rows[0, 1, 2, 3, 4, 5]

swapping 0 and 3 yields

rows[3, 1, 2, 0, 4, 5]

accessing the 0th row now is like
matrixrow(rows[0])
 
Level 6
Joined
Aug 26, 2009
Messages
192
No, as already stated a user can perform such things by simply iterating over the matrix himself.
[...]
Actually I'm thinking of removing some methods as the library is already very big.

I would still add the usual algebraic operations. Negate, invert, add, multiply, subtract. These should be in such a package including the operations which one always needs for the given algebraic structure, here det, transpone, trace, maybe rank and a norm.
And then there should be something like a LinearAlgebra lib which can solve systems of linear equations and some other stuff. Just my opinion.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
I would still add the usual algebraic operations. Negate, invert, add, multiply, subtract.

Well, the usual algeraic operations are already implemented. I mean, you can easily negate the Matrix by doing matrix.multScalar(-1.0), the rest is already there.

And then there should be something like a LinearAlgebra lib which can solve systems of linear equations and some other stuff. Just my opinion.

Hm, yes that sounds like a good idea. I don't really like how big the library is at the moment, so I think spliting it up a bit makes sense.
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
Has one tried using Vectors as rows? I found a C library that uses Vector2 and Vector3 for Matrix2, Matrix3 and Matrix4

Whats the benefit? Its slower and more complicated. The only benefit i could imagine is that very sparse matrices could, in some cases, be more efficiently represented (memory wise). But those are very unlikely situations. (And for sparse matrices there are even more efficient representations)
 
Here's something useful:

JASS:
function MatrixPow takes Matrix m, integer b returns Matrix
    local Matrix r = Matrix.create(m.n, m.m)
    local Matrix a = m.assign()
    call r.eye()
    loop
        exitwhen b == 0
        if b/2*2 != b then
            set r = r.multiply(a)
        endif
        set a = a.multiply(a)
        set b = b / 2
    endloop
    return r
endfunction

This does exponentiation with O(log b) matrix multiplications.
I use these kinds of algorithms all the time when I'm working with recurrence relations.

Of course, the above is usually more useful when you augment it with an extra parameter 'mod' so that you'd have a MatrixPowMod function.

You can compute the 10^500th Fibonacci number modulo 1 000 000 007 pretty easily :)
(Without using Pisano periods)
 
Top