using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace VisualMath.Accord.Math { using System; using System.Collections.Generic; using System.Data; using System.Linq; using VisualMath.Accord.Math.Decompositions; using AForge; using AForge.Math; using AForge.Math.Random; /// /// Static class Matrix. Defines a set of extension methods /// that operates mainly on multidimensional arrays and vectors. /// public static class Matrix { #region Comparison and Rounding /// /// Compares two matrices for equality, considering an acceptance threshold. /// public static bool IsEqual(this double[,] a, double[,] b, double threshold) { for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < b.GetLength(1); j++) { double x = a[i, j], y = b[i, j]; if (System.Math.Abs(x - y) > threshold || (Double.IsNaN(x) ^ Double.IsNaN(y))) return false; } } return true; } /// /// Compares two matrices for equality, considering an acceptance threshold. /// public static bool IsEqual(this float[,] a, float[,] b, float threshold) { for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < b.GetLength(1); j++) { float x = a[i, j], y = b[i, j]; if (System.Math.Abs(x - y) > threshold || (Single.IsNaN(x) ^ Single.IsNaN(y))) return false; } } return true; } /// /// Compares two matrices for equality, considering an acceptance threshold. /// public static bool IsEqual(this double[][] a, double[][] b, double threshold) { for (int i = 0; i < a.Length; i++) { for (int j = 0; j < a[i].Length; j++) { double x = a[i][j], y = b[i][j]; if (System.Math.Abs(x - y) > threshold || (Double.IsNaN(x) ^ Double.IsNaN(y))) { return false; } } } return true; } /// /// Compares two vectors for equality, considering an acceptance threshold. /// public static bool IsEqual(this double[] a, double[] b, double threshold) { for (int i = 0; i < a.Length; i++) { if (System.Math.Abs(a[i] - b[i]) > threshold) return false; } return true; } /// /// Compares each member of a vector for equality with a scalar value x. /// public static bool IsEqual(this double[] a, double x) { for (int i = 0; i < a.Length; i++) { if (a[i] != x) return false; } return true; } /// /// Compares each member of a matrix for equality with a scalar value x. /// public static bool IsEqual(this double[,] a, double x) { for (int i = 0; i < a.GetLength(0); i++) { for (int j = 0; j < a.GetLength(1); j++) { if (a[i, j] != x) return false; } } return true; } /// /// Compares two matrices for equality. /// public static bool IsEqual(this T[][] a, T[][] b) { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) { if (a[i] == b[i]) continue; if (a[i] == null || b[i] == null) return false; if (a[i].Length != b[i].Length) return false; for (int j = 0; j < a[i].Length; j++) { if (!a[i][j].Equals(b[i][j])) return false; } } return true; } /// Compares two matrices for equality. public static bool IsEqual(this T[,] a, T[,] b) { if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1)) return false; int rows = a.GetLength(0); int cols = a.GetLength(1); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (!a[i, j].Equals(b[i, j])) return false; } } return true; } /// Compares two vectors for equality. public static bool IsEqual(this T[] a, params T[] b) { if (a.Length != b.Length) return false; for (int i = 0; i < a.Length; i++) { if (!a[i].Equals(b[i])) return false; } return true; } /// /// This method should not be called. Use Matrix.IsEqual instead. /// public static new bool Equals(object value) { throw new NotSupportedException("Use Matrix.IsEqual instead."); } #endregion #region Matrix Algebra /// /// Gets the transpose of a matrix. /// /// A matrix. /// The transpose of matrix m. public static T[,] Transpose(this T[,] value) { int rows = value.GetLength(0); int cols = value.GetLength(1); T[,] t = new T[cols, rows]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) t[j, i] = value[i, j]; return t; } /// /// Gets the transpose of a row vector. /// /// A row vector. /// The transpose of the vector. public static T[,] Transpose(this T[] value) { T[,] t = new T[value.Length, 1]; for (int i = 0; i < value.Length; i++) t[i, 0] = value[i]; return t; } #region Multiplication /// /// Multiplies two matrices. /// /// The left matrix. /// The right matrix. /// The product of the multiplication of the two matrices. public static double[,] Multiply(this double[,] a, double[,] b) { double[,] r = new double[a.GetLength(0), b.GetLength(1)]; Multiply(a, b, r); return r; } /// /// Multiplies two matrices. /// /// The left matrix. /// The right matrix. /// The matrix to store results. public static unsafe void Multiply(this double[,] a, double[,] b, double[,] r) { int n = a.GetLength(1); int m = a.GetLength(0); int p = b.GetLength(1); fixed (double* ptrA = a) { double[] Bcolj = new double[n]; for (int j = 0; j < p; j++) { for (int k = 0; k < n; k++) Bcolj[k] = b[k, j]; double* Arowi = ptrA; for (int i = 0; i < m; i++) { double s = 0; for (int k = 0; k < n; k++) s += *(Arowi++) * Bcolj[k]; r[i, j] = s; } } } } /// /// Multiplies two matrices. /// /// The left matrix. /// The right matrix. /// The product of the multiplication of the two matrices. public static float[,] Multiply(this float[,] a, float[,] b) { float[,] r = new float[a.GetLength(0), b.GetLength(1)]; Multiply(a, b, r); return r; } /// /// Multiplies two matrices. /// /// The left matrix. /// The right matrix. /// The matrix to store results. public static unsafe void Multiply(this float[,] a, float[,] b, float[,] r) { int acols = a.GetLength(1); int arows = a.GetLength(0); int bcols = b.GetLength(1); fixed (float* ptrA = a) { float[] Bcolj = new float[acols]; for (int j = 0; j < bcols; j++) { for (int k = 0; k < acols; k++) Bcolj[k] = b[k, j]; float* Arowi = ptrA; for (int i = 0; i < arows; i++) { float s = 0; for (int k = 0; k < acols; k++) s += *(Arowi++) * Bcolj[k]; r[i, j] = s; } } } } /// /// Multiplies a row vector and a matrix. /// /// A row vector. /// A matrix. /// The product of the multiplication of the row vector and the matrix. public static double[] Multiply(this double[] a, double[,] b) { if (b.GetLength(0) != a.Length) throw new ArgumentException("Matrix dimensions must match", "b"); double[] r = new double[b.GetLength(1)]; for (int j = 0; j < b.GetLength(1); j++) for (int k = 0; k < a.Length; k++) r[j] += a[k] * b[k, j]; return r; } /// /// Multiplies a matrix and a vector (a*bT). /// /// A matrix. /// A column vector. /// The product of the multiplication of matrix a and column vector b. public static double[] Multiply(this double[,] a, double[] b) { if (a.GetLength(1) != b.Length) throw new ArgumentException("Matrix dimensions must match", "b"); double[] r = new double[a.GetLength(0)]; for (int i = 0; i < a.GetLength(0); i++) for (int j = 0; j < b.Length; j++) r[i] += a[i, j] * b[j]; return r; } /// /// Multiplies a matrix by a scalar. /// /// A matrix. /// A scalar. /// The product of the multiplication of matrix a and scalar x. public static double[,] Multiply(this double[,] a, double x) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] * x; return r; } /// /// Multiplies a vector by a scalar. /// /// A vector. /// A scalar. /// The product of the multiplication of vector a and scalar x. public static double[] Multiply(this double[] a, double x) { double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] * x; return r; } /// /// Multiplies a matrix by a scalar. /// /// A scalar. /// A matrix. /// The product of the multiplication of vector a and scalar x. public static double[,] Multiply(this double x, double[,] a) { return a.Multiply(x); } /// /// Multiplies a vector by a scalar. /// /// A scalar. /// A matrix. /// The product of the multiplication of vector a and scalar x. public static double[] Multiply(this double x, double[] a) { return a.Multiply(x); } #endregion #region Division /// /// Divides a vector by a scalar. /// /// A vector. /// A scalar. /// The division quotient of vector a and scalar x. public static double[] Divide(this double[] a, double x) { double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] / x; return r; } /// /// Divides two matrices by multiplying A by the inverse of B. /// /// The first matrix. /// The second matrix (which will be inverted). /// The result from the division of a and b. public static double[,] Divide(this double[,] a, double[,] b) { //return a.Multiply(b.Inverse()); if (a.GetLength(0) == a.GetLength(1)) { // Solve by LU Decomposition if matrix is square. return new LuDecomposition(b, true).SolveTranspose(a); } else { // Solve by QR Decomposition if not. return new QrDecomposition(b, true).SolveTranspose(a); } } /// /// Divides a matrix by a scalar. /// /// A matrix. /// A scalar. /// The division quotient of matrix a and scalar x. public static double[,] Divide(this double[,] a, double x) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] / x; return r; } #endregion #region Products /// /// Gets the inner product (scalar product) between two vectors (aT*b). /// /// A vector. /// A vector. /// The inner product of the multiplication of the vectors. /// /// In mathematics, the dot product is an algebraic operation that takes two /// equal-length sequences of numbers (usually coordinate vectors) and returns /// a single number obtained by multiplying corresponding entries and adding up /// those products. The name is derived from the dot that is often used to designate /// this operation; the alternative name scalar product emphasizes the scalar /// (rather than vector) nature of the result. /// /// The principal use of this product is the inner product in a Euclidean vector space: /// when two vectors are expressed on an orthonormal basis, the dot product of their /// coordinate vectors gives their inner product. /// public static double InnerProduct(this double[] a, double[] b) { double r = 0.0; if (a.Length != b.Length) throw new ArgumentException("Vector dimensions must match", "b"); for (int i = 0; i < a.Length; i++) r += a[i] * b[i]; return r; } /// /// Gets the outer product (matrix product) between two vectors (a*bT). /// /// /// In linear algebra, the outer product typically refers to the tensor /// product of two vectors. The result of applying the outer product to /// a pair of vectors is a matrix. The name contrasts with the inner product, /// which takes as input a pair of vectors and produces a scalar. /// public static double[,] OuterProduct(this double[] a, double[] b) { double[,] r = new double[a.Length, b.Length]; for (int i = 0; i < a.Length; i++) for (int j = 0; j < b.Length; j++) r[i, j] += a[i] * b[j]; return r; } /// /// Vectorial product. /// /// /// The cross product, vector product or Gibbs vector product is a binary operation /// on two vectors in three-dimensional space. It has a vector result, a vector which /// is always perpendicular to both of the vectors being multiplied and the plane /// containing them. It has many applications in mathematics, engineering and physics. /// public static double[] VectorProduct(double[] a, double[] b) { return new double[] { a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0] }; } /// /// Vectorial product. /// public static float[] VectorProduct(float[] a, float[] b) { return new float[] { a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0] }; } /// /// Computes the cartesian product of many sets. /// /// /// References: /// - http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx /// public static IEnumerable> CartesianProduct(this IEnumerable> sequences) { IEnumerable> empty = new[] { Enumerable.Empty() }; return sequences.Aggregate(empty, (accumulator, sequence) => from accumulatorSequence in accumulator from item in sequence select accumulatorSequence.Concat(new[] { item })); } /// /// Computes the cartesian product of many sets. /// public static T[][] CartesianProduct(params T[][] sequences) { var result = CartesianProduct(sequences as IEnumerable>); List list = new List(); foreach (IEnumerable point in result) list.Add(point.ToArray()); return list.ToArray(); } /// /// Computes the cartesian product of two sets. /// public static T[][] CartesianProduct(this T[] sequence1, T[] sequence2) { return CartesianProduct(new T[][] { sequence1, sequence2 }); } #endregion #region Addition and Subraction /// /// Adds two matrices. /// /// A matrix. /// A matrix. /// The sum of the two matrices a and b. public static double[,] Add(this double[,] a, double[,] b) { if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1)) throw new ArgumentException("Matrix dimensions must match", "b"); int rows = a.GetLength(0); int cols = b.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] + b[i, j]; return r; } /// /// Adds a vector to a column or row of a matrix. /// /// A matrix. /// A vector. /// /// Pass 0 if the vector should be added row-wise, /// or 1 if the vector should be added column-wise. /// public static double[,] Add(this double[,] a, double[] b, int dimension) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; if (dimension == 1) { if (rows != b.Length) throw new ArgumentException( "Length of B should equal the number of rows in A", "b"); for (int j = 0; j < cols; j++) for (int i = 0; i < rows; i++) r[i, j] = a[i, j] + b[i]; } else { if (cols != b.Length) throw new ArgumentException( "Length of B should equal the number of cols in A", "b"); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] + b[j]; } return r; } /// /// Adds a vector to a column or row of a matrix. /// /// A matrix. /// A vector. /// The dimension to add the vector to. public static double[,] Subtract(this double[,] a, double[] b, int dimension) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; if (dimension == 1) { if (rows != b.Length) throw new ArgumentException( "Length of B should equal the number of rows in A", "b"); for (int j = 0; j < cols; j++) for (int i = 0; i < rows; i++) r[i, j] = a[i, j] - b[i]; } else { if (cols != b.Length) throw new ArgumentException( "Length of B should equal the number of cols in A", "b"); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] - b[j]; } return r; } /// /// Adds two vectors. /// /// A vector. /// A vector. /// The addition of vector a to vector b. public static double[] Add(this double[] a, double[] b) { if (a.Length != b.Length) throw new ArgumentException("Vector lengths must match", "b"); double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] + b[i]; return r; } /// /// Subtracts two matrices. /// /// A matrix. /// A matrix. /// The subtraction of matrix b from matrix a. public static double[,] Subtract(this double[,] a, double[,] b) { if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1)) throw new ArgumentException("Matrix dimensions must match", "b"); int rows = a.GetLength(0); int cols = b.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] - b[i, j]; return r; } /// /// Subtracts two vectors. /// /// A vector. /// A vector. /// The subtraction of vector b from vector a. public static double[] Subtract(this double[] a, double[] b) { if (a.Length != b.Length) throw new ArgumentException("Vector length must match", "b"); double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] - b[i]; return r; } /// /// Subtracts a scalar from a vector. /// /// A vector. /// A scalar. /// The subtraction of b from all elements in a. public static double[] Subtract(this double[] a, double b) { double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] - b; return r; } #endregion /// /// Multiplies a matrix by itself n times. /// public static double[,] Power(double[,] matrix, int n) { if (!matrix.IsSquare()) throw new ArgumentException("Matrix must be square", "matrix"); // TODO: This is a very naive implementation and should be optimized. double[,] r = matrix; for (int i = 0; i < n; i++) r = r.Multiply(matrix); return r; } #endregion #region Matrix Construction /// /// Creates a rows-by-cols matrix with uniformly distributed random data. /// public static double[,] Random(int rows, int cols) { return Random(rows, cols, 0, 1); } /// /// Creates a rows-by-cols matrix with uniformly distributed random data. /// public static double[,] Random(int size, bool symmetric, double minValue, double maxValue) { double[,] r = new double[size, size]; if (!symmetric) { for (int i = 0; i < size; i++) for (int j = 0; j < size; j++) r[i, j] = Accord.Math.Tools.Random.NextDouble() * (maxValue - minValue) + minValue; } else { for (int i = 0; i < size; i++) { for (int j = i; j < size; j++) { r[i, j] = Accord.Math.Tools.Random.NextDouble() * (maxValue - minValue) + minValue; r[j, i] = r[i, j]; } } } return r; } /// /// Creates a rows-by-cols matrix with uniformly distributed random data. /// public static double[,] Random(int rows, int cols, double minValue, double maxValue) { double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = Accord.Math.Tools.Random.NextDouble() * (maxValue - minValue) + minValue; return r; } /// /// Creates a rows-by-cols matrix random data drawn from a given distribution. /// public static double[,] Random(int rows, int cols, IRandomNumberGenerator generator) { double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = generator.Next(); return r; } /// /// Creates a vector with uniformly distributed random data. /// public static double[] Random(int size, double minValue, double maxValue) { double[] r = new double[size]; for (int i = 0; i < size; i++) r[i] = Accord.Math.Tools.Random.NextDouble() * (maxValue - minValue) + minValue; return r; } /// /// Creates a vector with random data drawn from a given distribution. /// public static double[] Random(int size, IRandomNumberGenerator generator) { double[] r = new double[size]; for (int i = 0; i < size; i++) r[i] = generator.Next(); return r; } /// /// Creates a magic square matrix. /// public static double[,] Magic(int size) { if (size < 3) throw new ArgumentException("The square size must be greater or equal to 3.", "size"); double[,] m = new double[size, size]; // First algorithm: Odd order if ((size % 2) == 1) { int a = (size + 1) / 2; int b = (size + 1); for (int j = 0; j < size; j++) for (int i = 0; i < size; i++) m[i, j] = size * ((i + j + a) % size) + ((i + 2 * j + b) % size) + 1; } // Second algorithm: Even order (double) else if ((size % 4) == 0) { for (int j = 0; j < size; j++) for (int i = 0; i < size; i++) if (((i + 1) / 2) % 2 == ((j + 1) / 2) % 2) m[i, j] = size * size - size * i - j; else m[i, j] = size * i + j + 1; } // Third algorithm: Even order (single) else { int n = size / 2; int p = (size - 2) / 4; double t; var a = Matrix.Magic(n); for (int j = 0; j < n; j++) { for (int i = 0; i < n; i++) { double e = a[i, j]; m[i, j] = e; m[i, j + n] = e + 2 * n * n; m[i + n, j] = e + 3 * n * n; m[i + n, j + n] = e + n * n; } } for (int i = 0; i < n; i++) { // Swap M[i,j] and M[i+n,j] for (int j = 0; j < p; j++) { t = m[i, j]; m[i, j] = m[i + n, j]; m[i + n, j] = t; } for (int j = size - p + 1; j < size; j++) { t = m[i, j]; m[i, j] = m[i + n, j]; m[i + n, j] = t; } } // Continue swaping in the boundary t = m[p, 0]; m[p, 0] = m[p + n, 0]; m[p + n, 0] = t; t = m[p, p]; m[p, p] = m[p + n, p]; m[p + n, p] = t; } return m; // return the magic square. } /// /// Gets the diagonal vector from a matrix. /// /// A matrix. /// The diagonal vector from matrix m. public static T[] Diagonal(this T[,] m) { T[] r = new T[m.GetLength(0)]; for (int i = 0; i < r.Length; i++) r[i] = m[i, i]; return r; } /// /// Returns a square diagonal matrix of the given size. /// public static T[,] Diagonal(int size, T value) { T[,] m = new T[size, size]; for (int i = 0; i < size; i++) m[i, i] = value; return m; } /// /// Returns a matrix of the given size with value on its diagonal. /// public static T[,] Diagonal(int rows, int cols, T value) { T[,] m = new T[rows, cols]; for (int i = 0; i < rows; i++) m[i, i] = value; return m; } /// /// Return a square matrix with a vector of values on its diagonal. /// public static T[,] Diagonal(T[] values) { T[,] m = new T[values.Length, values.Length]; for (int i = 0; i < values.Length; i++) m[i, i] = values[i]; return m; } /// /// Return a square matrix with a vector of values on its diagonal. /// public static T[,] Diagonal(int size, T[] values) { return Diagonal(size, size, values); } /// /// Returns a matrix with a vector of values on its diagonal. /// public static T[,] Diagonal(int rows, int cols, T[] values) { T[,] m = new T[rows, cols]; for (int i = 0; i < values.Length; i++) m[i, i] = values[i]; return m; } /// /// Returns a matrix with all elements set to a given value. /// public static T[,] Create(int rows, int cols, T value) { T[,] m = new T[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) m[i, j] = value; return m; } /// /// Returns a matrix with all elements set to a given value. /// public static T[,] Create(int size, T value) { return Create(size, size, value); } /// /// Expands a data vector given in summary form. /// /// A base vector. /// An array containing by how much each line should be replicated. /// public static T[] Expand(T[] data, int[] count) { var expansion = new List(); for (int i = 0; i < count.Length; i++) for (int j = 0; j < count[i]; j++) expansion.Add(data[i]); return expansion.ToArray(); } /// /// Expands a data matrix given in summary form. /// /// A base matrix. /// An array containing by how much each line should be replicated. /// public static T[][] Expand(T[][] data, int[] count) { var expansion = new List(); for (int i = 0; i < count.Length; i++) for (int j = 0; j < count[i]; j++) expansion.Add(data[i]); return expansion.ToArray(); } /// /// Expands a data matrix given in summary form. /// /// A base matrix. /// An array containing by how much each line should be replicated. /// public static T[,] Expand(T[,] data, int[] count) { var expansion = new List(); for (int i = 0; i < count.Length; i++) for (int j = 0; j < count[i]; j++) expansion.Add(data.GetRow(i)); return expansion.ToArray().ToMatrix(); } /// /// Returns the Identity matrix of the given size. /// public static double[,] Identity(int size) { return Diagonal(size, 1.0); } /// /// Creates a centering matrix of size n x n in the form (I - 1n) /// where 1n is a matrix with all entries 1/n. /// public static double[,] Centering(int size) { double[,] r = Matrix.Create(size, -1.0 / size); for (int i = 0; i < size; i++) r[i, i] = 1.0 - 1.0 / size; return r; } /// /// Creates a matrix with a single row vector. /// public static T[,] RowVector(params T[] values) { T[,] r = new T[1, values.Length]; for (int i = 0; i < values.Length; i++) r[0, i] = values[i]; return r; } /// /// Creates a matrix with a single column vector. /// public static T[,] ColumnVector(T[] values) { T[,] r = new T[values.Length, 1]; for (int i = 0; i < values.Length; i++) r[i, 0] = values[i]; return r; } /// /// Creates a index vector. /// public static int[] Indexes(int from, int to) { int[] r = new int[to - from]; for (int i = 0; i < r.Length; i++) r[i] = from++; return r; } /// /// Creates an interval vector. /// public static int[] Interval(int from, int to) { int[] r = new int[to - from + 1]; for (int i = 0; i < r.Length; i++) r[i] = from++; return r; } /// /// Creates an interval vector. /// public static double[] Interval(double from, double to, double stepSize) { double range = to - from; int steps = (int)Math.Ceiling(range / stepSize) + 1; double[] r = new double[steps]; for (int i = 0; i < r.Length; i++) r[i] = from + i * stepSize; return r; } /// /// Creates an interval vector. /// public static double[] Interval(double from, double to, int steps) { double range = to - from; double stepSize = range / steps; double[] r = new double[steps + 1]; for (int i = 0; i < r.Length; i++) r[i] = i * stepSize; return r; } /// /// Combines two vectors horizontally. /// public static T[] Combine(this T[] a1, T[] a2) { T[] r = new T[a1.Length + a2.Length]; for (int i = 0; i < a1.Length; i++) r[i] = a1[i]; for (int i = 0; i < a2.Length; i++) r[i + a1.Length] = a2[i]; return r; } /// /// Combines a vector and a element horizontally. /// public static T[] Combine(this T[] a1, T a2) { T[] r = new T[a1.Length + 1]; for (int i = 0; i < a1.Length; i++) r[i] = a1[i]; r[a1.Length] = a2; return r; } /// /// Combine vectors horizontally. /// public static T[] Combine(params T[][] vectors) { int size = 0; for (int i = 0; i < vectors.Length; i++) size += vectors[i].Length; T[] r = new T[size]; int c = 0; for (int i = 0; i < vectors.Length; i++) for (int j = 0; j < vectors[i].Length; j++) r[c++] = vectors[i][j]; return r; } /// /// Combines matrices vertically. /// public static T[,] Combine(params T[][,] matrices) { int rows = 0; int cols = 0; for (int i = 0; i < matrices.Length; i++) { rows += matrices[i].GetLength(0); if (matrices[i].GetLength(1) > cols) cols = matrices[i].GetLength(1); } T[,] r = new T[rows, cols]; int c = 0; for (int i = 0; i < matrices.Length; i++) { for (int j = 0; j < matrices[i].GetLength(0); j++) { for (int k = 0; k < matrices[i].GetLength(1); k++) r[c, k] = matrices[i][j, k]; c++; } } return r; } /// /// Combines matrices vertically. /// public static T[][] Combine(params T[][][] matrices) { int rows = 0; int cols = 0; for (int i = 0; i < matrices.Length; i++) { rows += matrices[i].Length; if (matrices[i][0].Length > cols) cols = matrices[i][0].Length; } T[][] r = new T[rows][]; for (int i = 0; i < rows; i++) r[i] = new T[cols]; int c = 0; for (int i = 0; i < matrices.Length; i++) { for (int j = 0; j < matrices[i].Length; j++) { for (int k = 0; k < matrices[i][0].Length; k++) r[c][k] = matrices[i][j][k]; c++; } } return r; } #endregion #region Subsection and elements selection /// Returns a sub matrix extracted from the current matrix. /// The matrix to return the submatrix from. /// Start row index /// End row index /// Start column index /// End column index /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[,] Submatrix(this T[,] data, int startRow, int endRow, int startColumn, int endColumn) { int rows = data.GetLength(0); int cols = data.GetLength(1); if ((startRow > endRow) || (startColumn > endColumn) || (startRow < 0) || (startRow >= rows) || (endRow < 0) || (endRow >= rows) || (startColumn < 0) || (startColumn >= cols) || (endColumn < 0) || (endColumn >= cols)) { throw new ArgumentException("Argument out of range."); } T[,] X = new T[endRow - startRow + 1, endColumn - startColumn + 1]; for (int i = startRow; i <= endRow; i++) { for (int j = startColumn; j <= endColumn; j++) { X[i - startRow, j - startColumn] = data[i, j]; } } return X; } /// Returns a sub matrix extracted from the current matrix. /// The matrix to return the submatrix from. /// Array of row indices. Pass null to select all indices. /// Array of column indices. Pass null to select all indices. /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[,] Submatrix(this T[,] data, int[] rowIndexes, int[] columnIndexes) { if (rowIndexes == null) rowIndexes = Indexes(0, data.GetLength(0)); if (columnIndexes == null) columnIndexes = Indexes(0, data.GetLength(1)); T[,] X = new T[rowIndexes.Length, columnIndexes.Length]; for (int i = 0; i < rowIndexes.Length; i++) { for (int j = 0; j < columnIndexes.Length; j++) { if ((rowIndexes[i] < 0) || (rowIndexes[i] >= data.GetLength(0)) || (columnIndexes[j] < 0) || (columnIndexes[j] >= data.GetLength(1))) { throw new ArgumentException("Argument out of range."); } X[i, j] = data[rowIndexes[i], columnIndexes[j]]; } } return X; } /// Returns a sub matrix extracted from the current matrix. /// The matrix to return the submatrix from. /// Array of row indices /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[,] Submatrix(this T[,] data, int[] rowIndexes) { T[,] X = new T[rowIndexes.Length, data.GetLength(1)]; for (int i = 0; i < rowIndexes.Length; i++) { for (int j = 0; j < data.GetLength(1); j++) { if ((rowIndexes[i] < 0) || (rowIndexes[i] >= data.GetLength(0))) { throw new ArgumentException("Argument out of range."); } X[i, j] = data[rowIndexes[i], j]; } } return X; } /// Returns a subvector extracted from the current vector. /// The vector to return the subvector from. /// Array of indices. /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[] Submatrix(this T[] data, int[] indexes) { T[] X = new T[indexes.Length]; for (int i = 0; i < indexes.Length; i++) { X[i] = data[indexes[i]]; } return X; } /// Returns a sub matrix extracted from the current matrix. /// The vector to return the subvector from. /// Starting index. /// End index. /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[] Submatrix(this T[] data, int i0, int i1) { T[] X = new T[i1 - i0 + 1]; for (int i = i0; i <= i1; i++) { X[i - i0] = data[i]; } return X; } /// Returns a sub matrix extracted from the current matrix. /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[] Submatrix(this T[] data, int first) { if (first < 1 || first > data.Length) throw new ArgumentOutOfRangeException("first"); return Submatrix(data, 0, first - 1); } /// Returns a sub matrix extracted from the current matrix. /// The matrix to return the submatrix from. /// Starting row index /// End row index /// Array of column indices /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[,] Submatrix(this T[,] data, int i0, int i1, int[] c) { if ((i0 > i1) || (i0 < 0) || (i0 >= data.GetLength(0)) || (i1 < 0) || (i1 >= data.GetLength(0))) { throw new ArgumentException("Argument out of range."); } T[,] X = new T[i1 - i0 + 1, c.Length]; for (int i = i0; i <= i1; i++) { for (int j = 0; j < c.Length; j++) { if ((c[j] < 0) || (c[j] >= data.GetLength(1))) { throw new ArgumentException("Argument out of range."); } X[i - i0, j] = data[i, c[j]]; } } return X; } /// Returns a sub matrix extracted from the current matrix. /// The matrix to return the submatrix from. /// Array of row indices /// Start column index /// End column index /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[,] Submatrix(this T[,] data, int[] r, int j0, int j1) { if ((j0 > j1) || (j0 < 0) || (j0 >= data.GetLength(1)) || (j1 < 0) || (j1 >= data.GetLength(1))) { throw new ArgumentException("Argument out of range."); } T[,] X = new T[r.Length, j1 - j0 + 1]; for (int i = 0; i < r.Length; i++) { for (int j = j0; j <= j1; j++) { if ((r[i] < 0) || (r[i] >= data.GetLength(0))) { throw new ArgumentException("Argument out of range."); } X[i, j - j0] = data[r[i], j]; } } return X; } /// Returns a sub matrix extracted from the current matrix. /// The matrix to return the submatrix from. /// Starting row index /// End row index /// Array of column indices /// /// Routine adapted from Lutz Roeder's Mapack for .NET, September 2000. /// public static T[][] Submatrix(this T[][] data, int i0, int i1, int[] c) { if ((i0 > i1) || (i0 < 0) || (i0 >= data.Length) || (i1 < 0) || (i1 >= data.Length)) { throw new ArgumentException("Argument out of range"); } T[][] X = new T[i1 - i0 + 1][]; for (int i = i0; i <= i1; i++) { X[i] = new T[c.Length]; for (int j = 0; j < c.Length; j++) { if ((c[j] < 0) || (c[j] >= data[i].Length)) { throw new ArgumentException("Argument out of range."); } X[i - i0][j] = data[i][c[j]]; } } return X; } /// /// Returns a new matrix without one of its columns. /// public static T[][] RemoveColumn(this T[][] m, int index) { T[][] X = new T[m.Length][]; for (int i = 0; i < m.Length; i++) { X[i] = new T[m[i].Length - 1]; for (int j = 0; j < index; j++) { X[i][j] = m[i][j]; } for (int j = index + 1; j < m[i].Length; j++) { X[i][j - 1] = m[i][j]; } } return X; } /// /// Returns a new matrix with a given column vector inserted at a given index. /// public static T[,] InsertColumn(this T[,] m, T[] column, int index) { int rows = m.GetLength(0); int cols = m.GetLength(1); T[,] X = new T[rows, cols + 1]; for (int i = 0; i < rows; i++) { // Copy original matrix for (int j = 0; j < index; j++) { X[i, j] = m[i, j]; } for (int j = index; j < cols; j++) { X[i, j + 1] = m[i, j]; } // Copy additional column X[i, index] = column[i]; } return X; } /// /// Removes an element from a vector. /// public static T[] RemoveAt(this T[] array, int index) { T[] r = new T[array.Length - 1]; for (int i = 0; i < index; i++) r[i] = array[i]; for (int i = index; i < r.Length; i++) r[i] = array[i + 1]; return r; } /// /// Gets a column vector from a matrix. /// public static T[] GetColumn(this T[,] m, int index) { T[] column = new T[m.GetLength(0)]; for (int i = 0; i < column.Length; i++) column[i] = m[i, index]; return column; } /// /// Gets a column vector from a matrix. /// public static T[] GetColumn(this T[][] m, int index) { T[] column = new T[m.Length]; for (int i = 0; i < column.Length; i++) column[i] = m[i][index]; return column; } /// /// Stores a column vector into the given column position of the matrix. /// public static T[,] SetColumn(this T[,] m, int index, T[] column) { for (int i = 0; i < column.Length; i++) m[i, index] = column[i]; return m; } /// /// Gets a row vector from a matrix. /// public static T[] GetRow(this T[,] m, int index) { T[] row = new T[m.GetLength(1)]; for (int i = 0; i < row.Length; i++) row[i] = m[index, i]; return row; } /// /// Stores a row vector into the given row position of the matrix. /// public static T[,] SetRow(this T[,] m, int index, T[] row) { for (int i = 0; i < row.Length; i++) m[index, i] = row[i]; return m; } /// /// Gets the indices of all elements matching a certain criteria. /// /// The type of the array. /// The array to search inside. /// The search criteria. public static int[] Find(this T[] data, Func func) { return Find(data, func, false); } /// /// Gets the indices of all elements matching a certain criteria. /// /// The type of the array. /// The array to search inside. /// The search criteria. /// /// Set to true to stop when the first element is /// found, set to false to get all elements. /// public static int[] Find(this T[] data, Func func, bool firstOnly) { List idx = new List(); for (int i = 0; i < data.Length; i++) { if (func(data[i])) { if (firstOnly) return new int[] { i }; else idx.Add(i); } } return idx.ToArray(); } /// /// Gets the indices of all elements matching a certain criteria. /// /// The type of the array. /// The array to search inside. /// The search criteria. public static int[][] Find(this T[,] data, Func func) { return Find(data, func, false); } /// /// Gets the indices of all elements matching a certain criteria. /// /// The type of the array. /// The array to search inside. /// The search criteria. /// /// Set to true to stop when the first element is /// found, set to false to get all elements. /// public static int[][] Find(this T[,] data, Func func, bool firstOnly) { List idx = new List(); for (int i = 0; i < data.GetLength(0); i++) { for (int j = 0; j < data.GetLength(1); j++) { if (func(data[i, j])) { if (firstOnly) return new int[][] { new int[] { i, j } }; else idx.Add(new int[] { i, j }); } } } return idx.ToArray(); } /// /// Applies a function to every element of the array. /// public static TResult[] Apply(this TData[] data, Func func) { var r = new TResult[data.Length]; for (int i = 0; i < data.Length; i++) r[i] = func(data[i]); return r; } /// /// Applies a function to every element of a matrix. /// public static TResult[,] Apply(this TData[,] data, Func func) { int rows = data.GetLength(0); int cols = data.GetLength(1); var r = new TResult[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = func(data[i, j]); return r; } /// /// Applies a function to every element of the array. /// public static void ApplyInPlace(this TData[] data, Func func) { for (int i = 0; i < data.Length; i++) data[i] = func(data[i]); } /// /// Applies a function to every element of the array. /// public static void ApplyInPlace(this TData[] data, Func func) { for (int i = 0; i < data.Length; i++) data[i] = func(data[i], i); } /// /// Sorts the columns of a matrix by sorting keys. /// /// The key value for each column. /// The matrix to be sorted. /// The comparer to use. public static TValue[,] Sort(TKey[] keys, TValue[,] values, IComparer comparer) { int[] indices = new int[keys.Length]; for (int i = 0; i < keys.Length; i++) indices[i] = i; Array.Sort(keys, indices, comparer); return values.Submatrix(0, values.GetLength(0) - 1, indices); } /// /// Splits a given vector into a smaller vectors of the given size. /// /// The vector to be splitted. /// The size of the resulting vectors. /// An array of vectors containing the subdivisions of the given vector. public static T[][] Split(this T[] vector, int size) { int n = vector.Length / size; T[][] r = new T[n][]; for (int i = 0; i < n; i++) { T[] ri = r[i] = new T[size]; for (int j = 0; j < size; j++) ri[j] = vector[j * n + i]; } return r; } #endregion #region Matrix Characteristics /// /// Returns true if a matrix is square. /// public static bool IsSquare(this T[,] matrix) { return matrix.GetLength(0) == matrix.GetLength(1); } /// /// Returns true if a matrix is symmetric. /// /// /// public static bool IsSymmetric(this double[,] matrix) { if (matrix.GetLength(0) == matrix.GetLength(1)) { for (int i = 0; i < matrix.GetLength(0); i++) { for (int j = 0; j <= i; j++) { if (matrix[i, j] != matrix[j, i]) return false; } } return true; } return false; } /// /// Gets the trace of a matrix. /// /// /// The trace of an n-by-n square matrix A is defined to be the sum of the /// elements on the main diagonal (the diagonal from the upper left to the /// lower right) of A. /// public static double Trace(this double[,] m) { double trace = 0.0; for (int i = 0; i < m.GetLength(0); i++) trace += m[i, i]; return trace; } /// /// Gets the determinant of a matrix. /// public static double Determinant(this double[,] m) { return new LuDecomposition(m).Determinant; } /// /// Gets whether a matrix is positive definite. /// public static bool IsPositiveDefinite(this double[,] m) { return new CholeskyDecomposition(m).PositiveDefinite; } /// Calculates a vector cumulative sum. public static double[] CumulativeSum(this double[] value) { double[] sum = new double[value.Length]; sum[0] = value[0]; for (int i = 1; i < value.Length; i++) sum[i] += sum[i - 1] + value[i]; return sum; } /// Calculates the matrix Sum vector. /// A matrix whose sums will be calculated. /// The dimension in which the cumulative sum will be calculated. /// Returns a vector containing the sums of each variable in the given matrix. public static double[][] CumulativeSum(this double[,] value, int dimension) { double[][] sum; if (dimension == 1) { sum = new double[value.GetLength(0)][]; sum[0] = value.GetRow(0); // for each row for (int i = 1; i < value.GetLength(0); i++) { sum[i] = new double[value.GetLength(1)]; // for each column for (int j = 0; j < value.GetLength(1); j++) sum[i][j] += sum[i - 1][j] + value[i, j]; } } else if (dimension == 0) { sum = new double[value.GetLength(1)][]; sum[0] = value.GetColumn(0); // for each column for (int i = 1; i < value.GetLength(1); i++) { sum[i] = new double[value.GetLength(0)]; // for each row for (int j = 0; j < value.GetLength(0); j++) sum[i][j] += sum[i - 1][j] + value[j, i]; } } else { throw new ArgumentException("Invalid dimension", "dimension"); } return sum; } /// Calculates the matrix Sum vector. /// A matrix whose sums will be calculated. /// Returns a vector containing the sums of each variable in the given matrix. public static double[] Sum(this double[,] value) { return Sum(value, 0); } /// Calculates the matrix Sum vector. /// A matrix whose sums will be calculated. /// The dimension in which the sum will be calculated. /// Returns a vector containing the sums of each variable in the given matrix. public static double[] Sum(this double[,] value, int dimension) { int rows = value.GetLength(0); int cols = value.GetLength(1); double[] sum; if (dimension == 0) { sum = new double[cols]; for (int j = 0; j < cols; j++) { double s = 0.0; for (int i = 0; i < rows; i++) s += value[i, j]; sum[j] = s; } } else if (dimension == 1) { sum = new double[rows]; for (int j = 0; j < rows; j++) { double s = 0.0; for (int i = 0; i < cols; i++) s += value[j, i]; sum[j] = s; } } else { throw new ArgumentException("Invalid dimension", "dimension"); } return sum; } /// Calculates the matrix Sum vector. /// A matrix whose sums will be calculated. /// Returns a vector containing the sums of each variable in the given matrix. public static int[] Sum(int[,] value) { return Sum(value, 0); } /// Calculates the matrix Sum vector. /// A matrix whose sums will be calculated. /// The dimension in which the sum will be calculated. /// Returns a vector containing the sums of each variable in the given matrix. public static int[] Sum(this int[,] value, int dimension) { int rows = value.GetLength(0); int cols = value.GetLength(1); int[] sum; if (dimension == 0) { sum = new int[cols]; for (int j = 0; j < cols; j++) { int s = 0; for (int i = 0; i < rows; i++) s += value[i, j]; sum[j] = s; } } else if (dimension == 1) { sum = new int[rows]; for (int j = 0; j < rows; j++) { int s = 0; for (int i = 0; i < cols; i++) s += value[j, i]; sum[j] = s; } } else { throw new ArgumentException("Invalid dimension", "dimension"); } return sum; } /// /// Gets the sum of all elements in a vector. /// public static double Sum(this double[] value) { double sum = 0.0; for (int i = 0; i < value.Length; i++) sum += value[i]; return sum; } /// /// Gets the product of all elements in a vector. /// public static double Product(this double[] value) { double product = 1.0; for (int i = 0; i < value.Length; i++) product *= value[i]; return product; } /// /// Gets the sum of all elements in a vector. /// public static int Sum(this int[] value) { int sum = 0; for (int i = 0; i < value.Length; i++) sum += value[i]; return sum; } /// /// Gets the product of all elements in a vector. /// public static int Product(this int[] value) { int product = 1; for (int i = 0; i < value.Length; i++) product *= value[i]; return product; } /// /// Gets the maximum element in a vector. /// public static T Max(this T[] values, out int imax) where T : IComparable { imax = 0; T max = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i].CompareTo(max) > 0) { max = values[i]; imax = i; } } return max; } /// /// Gets the maximum element in a vector. /// public static T Max(this T[] values) where T : IComparable { int imax = 0; T max = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i].CompareTo(max) > 0) { max = values[i]; imax = i; } } return max; } /// /// Gets the maximum element in a vector. /// public static double Max(this double[] vector) { double max = vector[0]; for (int i = 0; i < vector.Length; i++) { if (vector[i] > max) max = vector[i]; } return max; } /// /// Gets the minimum element in a vector. /// public static double Min(this double[] values) { double min = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i] < min) min = values[i]; } return min; } /// /// Gets the maximum element in a vector. /// public static double Max(this double[] values, out int imax) { imax = 0; double max = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i] > max) { max = values[i]; imax = i; } } return max; } /// /// Gets the minimum element in a vector. /// public static double Min(this double[] values, out int imin) { imin = 0; double min = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i] < min) { min = values[i]; imin = i; } } return min; } /// /// Gets the maximum element in a vector. /// public static float Max(this float[] values) { float max = values[0]; for (int i = 0; i < values.Length; i++) { if (values[i] > max) max = values[i]; } return max; } /// /// Gets the minimum element in a vector. /// public static float Min(this float[] values) { float min = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i] < min) min = values[i]; } return min; } /// /// Gets the maximum element in a vector. /// public static int Max(this int[] values) { int max = values[0]; for (int i = 0; i < values.Length; i++) { if (values[i] > max) max = values[i]; } return max; } /// /// Gets the minimum element in a vector. /// public static int Min(this int[] values) { int min = values[0]; for (int i = 1; i < values.Length; i++) { if (values[i] < min) min = values[i]; } return min; } /// /// Gets the maximum values accross one dimension of a matrix. /// public static double[] Max(double[,] matrix, int dimension, out int[] imax) { int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); double[] max; if (dimension == 1) // Search down columns { imax = new int[rows]; max = matrix.GetColumn(0); for (int j = 0; j < rows; j++) { for (int i = 1; i < cols; i++) { if (matrix[j, i] > max[j]) { max[j] = matrix[j, i]; imax[j] = i; } } } } else { imax = new int[cols]; max = matrix.GetRow(0); for (int j = 0; j < cols; j++) { for (int i = 1; i < rows; i++) { if (matrix[i, j] > max[j]) { max[j] = matrix[i, j]; imax[j] = i; } } } } return max; } /// /// Gets the minimum values across one dimension of a matrix. /// public static double[] Min(double[,] matrix, int dimension, out int[] imin) { int rows = matrix.GetLength(0); int cols = matrix.GetLength(1); double[] min; if (dimension == 1) // Search down columns { imin = new int[rows]; min = matrix.GetColumn(0); for (int j = 0; j < rows; j++) { for (int i = 1; i < cols; i++) { if (matrix[j, i] < min[j]) { min[j] = matrix[j, i]; imin[j] = i; } } } } else { imin = new int[cols]; min = matrix.GetRow(0); for (int j = 0; j < cols; j++) { for (int i = 1; i < rows; i++) { if (matrix[i, j] < min[j]) { min[j] = matrix[i, j]; imin[j] = i; } } } } return min; } /// /// Gets the range of the values in a vector. /// public static DoubleRange Range(this double[] array) { double min = array[0]; double max = array[0]; for (int i = 1; i < array.Length; i++) { if (min > array[i]) min = array[i]; if (max < array[i]) max = array[i]; } return new DoubleRange(min, max); } /// /// Gets the range of the values in a vector. /// public static IntRange Range(this int[] array) { int min = array[0]; int max = array[0]; for (int i = 1; i < array.Length; i++) { if (min > array[i]) min = array[i]; if (max < array[i]) max = array[i]; } return new IntRange(min, max); } /// /// Gets the range of the values accross the columns of a matrix. /// public static DoubleRange[] Range(double[,] value) { DoubleRange[] ranges = new DoubleRange[value.GetLength(1)]; for (int j = 0; j < ranges.Length; j++) { double max = value[0, j]; double min = value[0, j]; for (int i = 0; i < value.GetLength(0); i++) { if (value[i, j] > max) max = value[i, j]; if (value[i, j] < min) min = value[i, j]; } ranges[j] = new DoubleRange(min, max); } return ranges; } #endregion #region Rounding and discretization /// /// Rounds a double-precision floating-point matrix to a specified number of fractional digits. /// public static double[,] Round(this double[,] a, int decimals) { double[,] r = new double[a.GetLength(0), a.GetLength(1)]; for (int i = 0; i < a.GetLength(0); i++) for (int j = 0; j < a.GetLength(1); j++) r[i, j] = System.Math.Round(a[i, j], decimals); return r; } /// /// Returns the largest integer less than or equal than to the specified /// double-precision floating-point number for each element of the matrix. /// public static double[,] Floor(this double[,] a) { double[,] r = new double[a.GetLength(0), a.GetLength(1)]; for (int i = 0; i < a.GetLength(0); i++) for (int j = 0; j < a.GetLength(1); j++) r[i, j] = System.Math.Floor(a[i, j]); return r; } /// /// Returns the largest integer greater than or equal than to the specified /// double-precision floating-point number for each element of the matrix. /// public static double[,] Ceiling(this double[,] a) { double[,] r = new double[a.GetLength(0), a.GetLength(1)]; for (int i = 0; i < a.GetLength(0); i++) for (int j = 0; j < a.GetLength(1); j++) r[i, j] = System.Math.Ceiling(a[i, j]); return r; } /// /// Rounds a double-precision floating-point number array to a specified number of fractional digits. /// public static double[] Round(double[] value, int decimals) { double[] r = new double[value.Length]; for (int i = 0; i < r.Length; i++) r[i] = Math.Round(value[i], decimals); return r; } /// /// Returns the largest integer less than or equal than to the specified /// double-precision floating-point number for each element of the array. /// public static double[] Floor(double[] value) { double[] r = new double[value.Length]; for (int i = 0; i < r.Length; i++) r[i] = Math.Floor(value[i]); return r; } /// /// Returns the largest integer greater than or equal than to the specified /// double-precision floating-point number for each element of the array. /// public static double[] Ceiling(double[] value) { double[] r = new double[value.Length]; for (int i = 0; i < r.Length; i++) r[i] = Math.Ceiling(value[i]); return r; } #endregion #region Elementwise operations /// /// Elementwise absolute value. /// public static int[] Abs(this int[] value) { int[] r = new int[value.Length]; for (int i = 0; i < value.Length; i++) r[i] = System.Math.Abs(value[i]); return r; } /// /// Elementwise absolute value. /// public static double[] Abs(this double[] value) { double[] r = new double[value.Length]; for (int i = 0; i < value.Length; i++) r[i] = System.Math.Abs(value[i]); return r; } /// /// Elementwise absolute value. /// public static double[,] Abs(this double[,] value) { int rows = value.GetLength(0); int cols = value.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = System.Math.Abs(value[i, j]); return r; } /// /// Elementwise absolute value. /// public static int[,] Abs(this int[,] value) { int rows = value.GetLength(0); int cols = value.GetLength(1); int[,] r = new int[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = System.Math.Abs(value[i, j]); return r; } /// /// Elementwise Square root. /// public static double[] Sqrt(this double[] value) { double[] r = new double[value.Length]; for (int i = 0; i < value.Length; i++) r[i] = System.Math.Sqrt(value[i]); return r; } /// /// Elementwise Square root. /// public static double[,] Sqrt(this double[,] value) { int rows = value.GetLength(0); int cols = value.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = System.Math.Sqrt(value[i, j]); return r; } /// /// Elementwise power operation. /// /// A matrix. /// A power. /// Returns x elevated to the power of y. public static double[,] ElementwisePower(this double[,] x, double y) { double[,] r = new double[x.GetLength(0), x.GetLength(1)]; for (int i = 0; i < x.GetLength(0); i++) for (int j = 0; j < x.GetLength(1); j++) r[i, j] = System.Math.Pow(x[i, j], y); return r; } /// /// Elementwise power operation. /// /// A matrix. /// A power. /// Returns x elevated to the power of y. public static double[] ElementwisePower(this double[] x, double y) { double[] r = new double[x.Length]; for (int i = 0; i < r.Length; i++) r[i] = System.Math.Pow(x[i], y); return r; } /// /// Elementwise divide operation. /// public static double[] ElementwiseDivide(this double[] a, double[] b) { double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] / b[i]; return r; } /// /// Elementwise divide operation. /// public static double[,] ElementwiseDivide(this double[,] a, double[,] b) { int rows = a.GetLength(0); int cols = b.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] / b[i, j]; return r; } /// /// Elementwise division. /// public static double[,] ElementwiseDivide(this double[,] a, double[] b, int dimension) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; if (dimension == 1) { if (cols != b.Length) throw new ArgumentException( "Length of B should equal the number of columns in A", "b"); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] / b[j]; } else { if (rows != b.Length) throw new ArgumentException( "Length of B should equal the number of rows in A", "b"); for (int j = 0; j < cols; j++) for (int i = 0; i < rows; i++) r[i, j] = a[i, j] / b[i]; } return r; } /// /// Elementwise multiply operation. /// public static double[] ElementwiseMultiply(this double[] a, double[] b) { double[] r = new double[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] * b[i]; return r; } /// /// Elementwise multiply operation. /// public static double[,] ElementwiseMultiply(this double[,] a, double[,] b) { if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1)) throw new ArgumentException("Matrix dimensions must agree.", "b"); int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] * b[i, j]; return r; } /// /// Elementwise multiply operation. /// public static int[] ElementwiseMultiply(this int[] a, int[] b) { int[] r = new int[a.Length]; for (int i = 0; i < a.Length; i++) r[i] = a[i] * b[i]; return r; } /// /// Elementwise multiplication. /// public static int[,] ElementwiseMultiply(this int[,] a, int[,] b) { if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1)) throw new ArgumentException("Matrix dimensions must agree.", "b"); int rows = a.GetLength(0); int cols = a.GetLength(1); int[,] r = new int[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] * b[i, j]; return r; } /// /// Elementwise multiplication. /// public static double[,] ElementwiseMultiply(this double[,] a, double[] b, int dimension) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; if (dimension == 1) { if (cols != b.Length) throw new ArgumentException( "Length of B should equal the number of columns in A", "b"); for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = a[i, j] * b[j]; } else { if (rows != b.Length) throw new ArgumentException( "Length of B should equal the number of rows in A", "b"); for (int j = 0; j < cols; j++) for (int i = 0; i < rows; i++) r[i, j] = a[i, j] * b[i]; } return r; } #endregion #region Conversions /// /// Converts a jagged-array into a multidimensional array. /// public static T[,] ToMatrix(this T[][] array) { int rows = array.Length; if (rows == 0) return new T[rows, 0]; int cols = array[0].Length; T[,] m = new T[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) m[i, j] = array[i][j]; return m; } /// /// Converts an array into a multidimensional array. /// public static T[,] ToMatrix(this T[] array) { T[,] m = new T[1, array.Length]; for (int i = 0; i < array.Length; i++) m[0, i] = array[i]; return m; } /// /// Converts a multidimensional array into a jagged-array. /// public static T[][] ToArray(this T[,] matrix) { int rows = matrix.GetLength(0); T[][] array = new T[rows][]; for (int i = 0; i < rows; i++) array[i] = matrix.GetRow(i); return array; } /// /// Converts a DataTable to a double[,] array. /// public static double[,] ToMatrix(this DataTable table, out string[] columnNames) { double[,] m = new double[table.Rows.Count, table.Columns.Count]; columnNames = new string[table.Columns.Count]; for (int j = 0; j < table.Columns.Count; j++) { for (int i = 0; i < table.Rows.Count; i++) { if (table.Columns[j].DataType == typeof(System.String)) { m[i, j] = Double.Parse((String)table.Rows[i][j], System.Globalization.CultureInfo.InvariantCulture); } else if (table.Columns[j].DataType == typeof(System.Boolean)) { m[i, j] = (Boolean)table.Rows[i][j] ? 1.0 : 0.0; } else { m[i, j] = (Double)table.Rows[i][j]; } } columnNames[j] = table.Columns[j].Caption; } return m; } /// /// Converts a DataTable to a double[,] array. /// public static double[,] ToMatrix(this DataTable table) { String[] names; return ToMatrix(table, out names); } /// /// Converts a DataTable to a double[][] array. /// public static double[][] ToArray(this DataTable table) { double[][] m = new double[table.Rows.Count][]; for (int i = 0; i < table.Rows.Count; i++) { m[i] = new double[table.Columns.Count]; for (int j = 0; j < table.Columns.Count; j++) { if (table.Columns[j].DataType == typeof(System.String)) { m[i][j] = Double.Parse((String)table.Rows[i][j], System.Globalization.CultureInfo.InvariantCulture); } else if (table.Columns[j].DataType == typeof(System.Boolean)) { m[i][j] = (Boolean)table.Rows[i][j] ? 1.0 : 0.0; } else { m[i][j] = (Double)table.Rows[i][j]; } } } return m; } /// /// Converts a DataColumn to a double[] array. /// public static double[] ToArray(this DataColumn column) { double[] m = new double[column.Table.Rows.Count]; for (int i = 0; i < m.Length; i++) { object b = column.Table.Rows[i][column]; if (column.DataType == typeof(System.String)) { m[i] = Double.Parse((String)b, System.Globalization.CultureInfo.InvariantCulture); } else if (column.DataType == typeof(System.Boolean)) { m[i] = (Boolean)b ? 1.0 : 0.0; } else { m[i] = (Double)b; } } return m; } #endregion #region Inverses and Linear System Solving /// /// Returns the LHS solution matrix if the matrix is square or the least squares solution otherwise. /// /// /// Please note that this does not check if the matrix is non-singular before attempting to solve. /// public static double[,] Solve(this double[,] matrix, double[,] rightSide) { if (matrix.GetLength(0) == matrix.GetLength(1)) { // Solve by LU Decomposition if matrix is square. return new LuDecomposition(matrix).Solve(rightSide); } else { // Solve by QR Decomposition if not. return new QrDecomposition(matrix).Solve(rightSide); } } /// /// Returns the LHS solution vector if the matrix is square or the least squares solution otherwise. /// /// /// Please note that this does not check if the matrix is non-singular before attempting to solve. /// public static double[] Solve(this double[,] matrix, double[] rightSide) { if (matrix.GetLength(0) == matrix.GetLength(1)) { // Solve by LU Decomposition if matrix is square. return new LuDecomposition(matrix).Solve(rightSide); } else { // Solve by QR Decomposition if not. return new QrDecomposition(matrix).Solve(rightSide); } } /// /// Computes the inverse of a matrix. /// public static double[,] Inverse(this double[,] matrix) { if (matrix.GetLength(0) != matrix.GetLength(1)) throw new ArgumentException("Matrix must be square", "matrix"); return new LuDecomposition(matrix).Inverse(); } /// /// Computes the pseudo-inverse of a matrix. /// public static double[,] PseudoInverse(this double[,] matrix) { return new SingularValueDecomposition(matrix, true, true, true).Inverse(); } #endregion #region Morphological operations /// /// Transforms a vector into a matrix of given dimensions. /// public static T[,] Reshape(T[] array, int rows, int cols) { T[,] r = new T[rows, cols]; for (int j = 0, k = 0; j < cols; j++) for (int i = 0; i < rows; i++) r[i, j] = array[k++]; return r; } /// /// Transforms a vector into a single vector. /// public static T[] Reshape(T[,] array, int dimension) { int rows = array.GetLength(0); int cols = array.GetLength(1); T[] r = new T[rows * cols]; if (dimension == 1) { for (int j = 0, k = 0; j < rows; j++) for (int i = 0; i < cols; i++) r[k++] = array[j, i]; } else { for (int i = 0, k = 0; i < cols; i++) for (int j = 0; j < rows; j++) r[k++] = array[j, i]; } return r; } #endregion } }