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
}
}