src/classes/Matrix.ps1

# Need to parameterize class with "id" in order to re-load class during local testing
$Id = if ($Env:ProjectName -eq 'pwsh-prelude' -and $Env:BuildSystem -eq 'Unknown') { 'Test' } else { '' }
$TypeDefinition = @"
    using System;
    using System.Collections.Generic;
    using System.Linq;
 
    public class Matrix${Id} {
 
        public int[] Size {
            get;
            private set;
        }
        private double[][] _Rows;
        public double[][] Rows {
            get {
                return _Rows;
            }
            set {
                int rows = this.Size[0], cols = this.Size[1];
                if (value.Length > rows) {
                    var limit = Math.Min(value.Length,(rows * cols));
                    for (var i = 0; i < limit; ++i) {
                        int row = (int)(Math.Floor((double)(i / cols)));
                        int col = i % cols;
                        _Rows[row][col] = value[i][0];
                    }
                } else {
                    double[][] temp = Matrix${Id}.Create(rows,cols);
                    for (var row = 0; row < rows; ++row)
                        temp[row] = (double[])value[row].Take(cols).ToArray();
                    _Rows = temp;
                }
            }
        }
        public Matrix${Id}(int n) {
            this.Size = new int[] { n,n };
            this.Rows = Matrix${Id}.Create(n,n);
        }
        public Matrix${Id}(int rows,int cols) {
            this.Size = new int[] { rows,cols };
            this.Rows = Matrix${Id}.Create(rows,cols);
        }
        public static double[][] Create(int rows,int cols) {
            double[][] result = new double[rows][];
            for (int i = 0; i < rows; ++i)
                result[i] = new double[cols];
            return result;
        }
        public static Matrix${Id} Unit(int n) {
            var temp = new Matrix${Id}(n);
            foreach (var index in temp.Indexes()) {
                int i = index[0], j = index[1];
                temp.Rows[i][j] = 1;
            }
            return temp;
        }
        public static Matrix${Id} Identity(int n) {
            var temp = new Matrix${Id}(n);
            for (int i = 0; i < n; ++i)
                temp.Rows[i][i] = 1;
            return temp;
        }
        public static Matrix${Id} Transpose(Matrix${Id} a) {
            var temp = new Matrix${Id}(a.Size[1],a.Size[0]);
            foreach (var index in a.Indexes()) {
                int i = index[0], j = index[1];
                temp.Rows[j][i] = a.Rows[i][j];
            }
            return temp;
        }
        public static Matrix${Id} Add(params Matrix${Id}[] addends) {
            var size = addends[0].Size;
            var sum = new Matrix${Id}(size[0],size[1]);
            foreach (Matrix${Id} matrix in addends)
                foreach (var index in matrix.Indexes()) {
                    int i = index[0], j = index[1];
                    sum.Rows[i][j] += matrix.Rows[i][j];
                }
            return sum;
        }
        public static Matrix${Id} Adj(Matrix${Id} a) {
            Matrix${Id} temp = a.Clone();
            foreach (var index in temp.Indexes()) {
                int i = index[0], j = index[1];
                temp.Rows[i][j] = a.Cofactor(i,j);
            }
            return Matrix${Id}.Transpose(temp);
        }
        public static double Det(Matrix${Id} a) {
            int rows = a.Size[0];
            switch (rows) {
                case 1:
                    return a.Rows[0][0];
                case 2:
                    return (a.Rows[0][0] * a.Rows[1][1]) - (a.Rows[0][1] * a.Rows[1][0]);
                default:
                    double sum = 0;
                    for (int i = 0; i < rows; ++i)
                        sum += (a.Rows[0][i] * a.Cofactor(0,i));
                    return sum;
            }
        }
        public static Matrix${Id} Dot(Matrix${Id} a,Matrix${Id} b) {
            int m = a.Size[0], p = a.Size[1], n = b.Size[1];
            var product = new Matrix${Id}(m,n);
            foreach (var index in product.Indexes()) {
                int i = index[0], j = index[1];
                double sum = 0;
                for (int k = 0; k < p; ++k) {
                    sum += (a.Rows[i][k] * b.Rows[k][j]);
                }
                product.Rows[i][j] = sum;
            }
            return product;
        }
        public static Matrix${Id} Invert(Matrix${Id} a) {
            Matrix${Id} adjugate = Matrix${Id}.Adj(a);
            double det = Matrix${Id}.Det(a);
            return Matrix${Id}.Multiply(adjugate,(1 / det));
        }
        public static Matrix${Id} Multiply(Matrix${Id} a,double k) {
            Matrix${Id} clone = a.Clone();
            foreach (var index in clone.Indexes()) {
                int i = index[0], j = index[1];
                clone.Rows[i][j] *= k;
            }
            return clone;
        }
        public static double Trace(Matrix${Id} a) {
            double trace = 0;
            foreach (var index in a.Indexes()) {
                int i = index[0], j = index[1];
                if (i == j) {
                    trace += a.Rows[i][j];
                }
            }
            return trace;
        }
        public Matrix${Id} Clone() {
            Matrix${Id} original = this;
            int rows = original.Size[0], cols = original.Size[1];
            Matrix${Id} clone = new Matrix${Id}(rows,cols);
            foreach (var index in clone.Indexes()) {
                int i = index[0], j = index[1];
                clone.Rows[i][j] = original.Rows[i][j];
            }
            return clone;
        }
        public double Cofactor(int i = 0,int j = 0) {
            return (Math.Pow(-1,i + j) * Matrix${Id}.Det(this.RemoveRow(i).RemoveColumn(j)));
        }
        public List<int[]> Indexes(int offset = 0) {
            int rows = this.Size[0], cols = this.Size[1];
            List<int[]> pairs = new List<int[]>();
            for (var i = 0; i < rows; ++i)
                for (var j = 0; j < cols; ++j) {
                    int[] pair = { i + offset,j + offset };
                    pairs.Add(pair);
                }
            return pairs;
        }
        public Matrix${Id} RemoveColumn(int index) {
            Matrix${Id} original = this.Clone();
            int rows = original.Size[0], cols = original.Size[1];
            if (index < 0 || index >= cols) {
                return original;
            } else {
                var temp = new Matrix${Id}(rows,cols - 1);
                for (var i = 0; i < rows; ++i)
                    for (var j = 0; j < index; ++j)
                        temp.Rows[i][j] = original.Rows[i][j];
                for (var i = 0; i < rows; ++i)
                    for (var j = index; j < cols - 1; ++j)
                        temp.Rows[i][j] = original.Rows[i][j + 1];
                return temp;
            }
        }
        public Matrix${Id} RemoveRow(int index) {
            Matrix${Id} original = this.Clone();
            int rows = original.Size[0], cols = original.Size[1];
            if (index < 0 || index >= rows) {
                return original;
            } else {
                var temp = new Matrix${Id}(rows - 1,cols);
                for (var i = 0; i < index; ++i)
                    for (var j = 0; j < cols; ++j)
                        temp.Rows[i][j] = original.Rows[i][j];
                for (var i = index; i < rows - 1; ++i)
                    for (var j = 0; j < cols; ++j)
                        temp.Rows[i][j] = original.Rows[i + 1][j];
                return temp;
            }
        }
        public override string ToString() {
            Matrix${Id} matrix = this;
            int rank = matrix.Size[0];
            var rows = new string[rank];
            for (var i = 0; i < rank; ++i)
                rows[i] = string.Join(",",matrix.Rows[i]);
            return string.Join("\r\n",rows);
        }
    }
"@

if ("Matrix${Id}" -as [Type]) {
  return
} else {
  Add-Type -TypeDefinition $TypeDefinition
  if ($Env:BuildSystem -eq 'Travis CI') {
    $Accelerators = [PowerShell].Assembly.GetType('System.Management.Automation.TypeAccelerators')
    $Accelerators::Add('MatrixTest', 'Matrix')
  }
}