// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // Copyright (c) 2009-2010 Math.NET // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // namespace MathNet.Numerics.LinearAlgebra.Generic { using System; using Distributions; using Factorization; using Properties; /// /// Defines the base class for Matrix classes. /// public abstract partial class Matrix { /// /// The value of 1.0. /// private static readonly T One = Common.SetOne(); /// /// The value of 0.0. /// private static readonly T Zero = default(T); /// /// Adds another matrix to this matrix. /// /// The matrix to add to this matrix. /// The result of the addition. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public virtual Matrix Add(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other); } var result = CreateMatrix(RowCount, ColumnCount); DoAdd(other, result); return result; } /// /// Adds another matrix to this matrix. /// /// The matrix to add to this matrix. /// The matrix to store the result of the addition. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public virtual void Add(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } DoAdd(other, result); } /// /// Adds another matrix to this matrix. /// /// The matrix to add to this matrix. /// The matrix to store the result of the addition. /// If the other matrix is . /// If the two matrices don't have the same dimensions. protected abstract void DoAdd(Matrix other, Matrix result); /// /// Subtracts another matrix from this matrix. /// /// The matrix to subtract. /// The result of the subtraction. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public virtual Matrix Subtract(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other); } var result = CreateMatrix(RowCount, ColumnCount); DoSubtract(other, result); return result; } /// /// Subtracts another matrix from this matrix. /// /// The matrix to subtract. /// The matrix to store the result of the subtraction. /// If the other matrix is . /// If the two matrices don't have the same dimensions. public virtual void Subtract(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other); } DoSubtract(other, result); } /// /// Subtracts another matrix from this matrix. /// /// The matrix to subtract. /// The matrix to store the result of the subtraction. protected abstract void DoSubtract(Matrix other, Matrix result); /// /// Multiplies each element of this matrix with a scalar. /// /// The scalar to multiply with. /// The result of the multiplication. public virtual Matrix Multiply(T scalar) { if (scalar.Equals(One)) { return Clone(); } if (scalar.Equals(Zero)) { return CreateMatrix(RowCount, ColumnCount); } var result = CreateMatrix(RowCount, ColumnCount); DoMultiply(scalar, result); return result; } /// /// Multiplies each element of the matrix by a scalar and places results into the result matrix. /// /// The scalar to multiply the matrix with. /// The matrix to store the result of the multiplication. /// If the result matrix is . /// If the result matrix's dimensions are not the same as this matrix. public virtual void Multiply(T scalar, Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "result"); } if (result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "result"); } if (scalar.Equals(One)) { CopyTo(result); return; } if (scalar.Equals(Zero)) { result.Clear(); return; } DoMultiply(scalar, result); } /// /// Divides each element of this matrix with a scalar. /// /// The scalar to divide with. /// The result of the division. public virtual Matrix Divide(T scalar) { if (scalar.Equals(One)) { return Clone(); } if (scalar.Equals(Zero)) { throw new DivideByZeroException(); } var result = CreateMatrix(RowCount, ColumnCount); DoDivide(scalar, result); return result; } /// /// Divides each element of the matrix by a scalar and places results into the result matrix. /// /// The scalar to divide the matrix with. /// The matrix to store the result of the division. /// If the result matrix is . /// If the result matrix's dimensions are not the same as this matrix. public virtual void Divide(T scalar, Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount) { throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "result"); } if (result.ColumnCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "result"); } if (scalar.Equals(One)) { CopyTo(result); return; } if (scalar.Equals(Zero)) { throw new DivideByZeroException(); } DoDivide(scalar, result); } /// /// Divides each element of the matrix by a scalar and places results into the result matrix. /// /// The scalar to divide the matrix with. /// The matrix to store the result of the division. protected abstract void DoDivide(T scalar, Matrix result); /// /// Multiplies each element of the matrix by a scalar and places results into the result matrix. /// /// The scalar to multiply the matrix with. /// The matrix to store the result of the multiplication. protected abstract void DoMultiply(T scalar, Matrix result); /// /// Multiplies this matrix by a vector and returns the result. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If this.ColumnCount != rightSide.Count. public virtual Vector Multiply(Vector rightSide) { var ret = CreateVector(RowCount); Multiply(rightSide, ret); return ret; } /// /// Multiplies this matrix with a vector and places the results into the result vector. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If is . /// If result.Count != this.RowCount. /// If this.ColumnCount != .Count. public virtual void Multiply(Vector rightSide, Vector result) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (ColumnCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (RowCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(rightSide, result)) { var tmp = result.CreateVector(result.Count); Multiply(rightSide, tmp); tmp.CopyTo(result); } else { DoMultiply(rightSide, result); } } /// /// Multiplies this matrix with a vector and places the results into the result vector. /// /// The vector to multiply with. /// The result of the multiplication. protected abstract void DoMultiply(Vector rightSide, Vector result); /// /// Left multiply a matrix with a vector ( = vector * matrix ). /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If this.RowCount != .Count. public virtual Vector LeftMultiply(Vector leftSide) { var ret = CreateVector(ColumnCount); LeftMultiply(leftSide, ret); return ret; } /// /// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If the result matrix is . /// If result.Count != this.ColumnCount. /// If this.RowCount != .Count. public virtual void LeftMultiply(Vector leftSide, Vector result) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (RowCount != leftSide.Count) { throw DimensionsDontMatch(this, leftSide, "leftSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(leftSide, result)) { var tmp = result.CreateVector(result.Count); LeftMultiply(leftSide, tmp); tmp.CopyTo(result); } else { DoLeftMultiply(leftSide, result); } } /// /// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector. /// /// The vector to multiply with. /// The result of the multiplication. protected void DoLeftMultiply(Vector leftSide, Vector result) { DoTransposeThisAndMultiply(leftSide, result); } /// /// Multiplies this matrix with another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. /// If the other matrix is . /// If the result matrix is . /// If this.Columns != other.Rows. /// If the result matrix's dimensions are not the this.Rows x other.Columns. public virtual void Multiply(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != other.RowCount || result.RowCount != RowCount || result.ColumnCount != other.ColumnCount) { throw DimensionsDontMatch(this, other, result); } if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) { var tmp = result.CreateMatrix(result.RowCount, result.ColumnCount); Multiply(other, tmp); tmp.CopyTo(result); } else { DoMultiply(other, result); } } /// /// Multiplies this matrix with another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Columns != other.Rows. /// If the other matrix is . /// The result of the multiplication. public virtual Matrix Multiply(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (ColumnCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = CreateMatrix(RowCount, other.ColumnCount); Multiply(other, result); return result; } /// /// Multiplies this matrix with another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. protected abstract void DoMultiply(Matrix other, Matrix result); /// /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. /// If the other matrix is . /// If the result matrix is . /// If this.Columns != other.ColumnCount. /// If the result matrix's dimensions are not the this.RowCount x other.RowCount. public virtual void TransposeAndMultiply(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != other.ColumnCount || result.RowCount != RowCount || result.ColumnCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) { var tmp = result.CreateMatrix(result.RowCount, result.ColumnCount); TransposeAndMultiply(other, tmp); tmp.CopyTo(result); } else { DoTransposeAndMultiply(other, result); } } /// /// Multiplies this matrix with transpose of another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Columns != other.ColumnCount. /// If the other matrix is . /// The result of the multiplication. public virtual Matrix TransposeAndMultiply(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (ColumnCount != other.ColumnCount) { throw DimensionsDontMatch(this, other); } var result = CreateMatrix(RowCount, other.RowCount); TransposeAndMultiply(other, result); return result; } /// /// Multiplies this matrix with transpose of another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. protected abstract void DoTransposeAndMultiply(Matrix other, Matrix result); /// /// Multiplies the transpose of this matrix by a vector and returns the result. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If this.RowCount != rightSide.Count. public virtual Vector TransposeThisAndMultiply(Vector rightSide) { var ret = CreateVector(ColumnCount); TransposeThisAndMultiply(rightSide, ret); return ret; } /// /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. /// /// The vector to multiply with. /// The result of the multiplication. /// If is . /// If is . /// If result.Count != this.ColumnCount. /// If this.RowCount != .Count. public virtual void TransposeThisAndMultiply(Vector rightSide, Vector result) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (RowCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(rightSide, result)) { var tmp = result.CreateVector(result.Count); TransposeThisAndMultiply(rightSide, tmp); tmp.CopyTo(result); } else { DoTransposeThisAndMultiply(rightSide, result); } } /// /// Multiplies the transpose of this matrix with a vector and places the results into the result vector. /// /// The vector to multiply with. /// The result of the multiplication. protected abstract void DoTransposeThisAndMultiply(Vector rightSide, Vector result); /// /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. /// If the other matrix is . /// If the result matrix is . /// If this.Rows != other.RowCount. /// If the result matrix's dimensions are not the this.ColumnCount x other.ColumnCount. public virtual void TransposeThisAndMultiply(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (RowCount != other.RowCount || result.RowCount != ColumnCount || result.ColumnCount != other.ColumnCount) { throw DimensionsDontMatch(this, other, result); } if (ReferenceEquals(this, result) || ReferenceEquals(other, result)) { var tmp = result.CreateMatrix(result.RowCount, result.ColumnCount); TransposeThisAndMultiply(other, tmp); tmp.CopyTo(result); } else { DoTransposeThisAndMultiply(other, result); } } /// /// Multiplies the transpose of this matrix with another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Rows != other.RowCount. /// If the other matrix is . /// The result of the multiplication. public virtual Matrix TransposeThisAndMultiply(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (RowCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = CreateMatrix(ColumnCount, other.ColumnCount); TransposeThisAndMultiply(other, result); return result; } /// /// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. protected abstract void DoTransposeThisAndMultiply(Matrix other, Matrix result); /// /// Negate each element of this matrix. /// /// A matrix containing the negated values. public virtual Matrix Negate() { var result = CreateMatrix(RowCount, ColumnCount); DoNegate(result); return result; } /// /// Negate each element of this matrix and place the results into the result matrix. /// /// The result of the negation. /// If the result matrix is . /// if the result matrix's dimensions are not the same as this matrix. public virtual void Negate(Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result); } DoNegate(result); } /// /// Negate each element of this matrix and place the results into the result matrix. /// /// The result of the negation. protected abstract void DoNegate(Matrix result); /// /// Adds two matrices together and returns the results. /// /// This operator will allocate new memory for the result. It will /// choose the representation of either or depending on which /// is denser. /// The left matrix to add. /// The right matrix to add. /// The result of the addition. /// If and don't have the same dimensions. /// If or is . public static Matrix operator +(Matrix leftSide, Matrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (leftSide.RowCount != rightSide.RowCount || leftSide.ColumnCount != rightSide.ColumnCount) { throw DimensionsDontMatch(leftSide, rightSide); } return leftSide.Add(rightSide); } /// /// Returns a Matrix containing the same values of . /// /// The matrix to get the values from. /// A matrix containing a the same values as . /// If is . public static Matrix operator +(Matrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return rightSide.Clone(); } /// /// Subtracts two matrices together and returns the results. /// /// This operator will allocate new memory for the result. It will /// choose the representation of either or depending on which /// is denser. /// The left matrix to subtract. /// The right matrix to subtract. /// The result of the addition. /// If and don't have the same dimensions. /// If or is . public static Matrix operator -(Matrix leftSide, Matrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (leftSide.RowCount != rightSide.RowCount || leftSide.ColumnCount != rightSide.ColumnCount) { throw DimensionsDontMatch(leftSide, rightSide); } return leftSide.Subtract(rightSide); } /// /// Negates each element of the matrix. /// /// The matrix to negate. /// A matrix containing the negated values. /// If is . public static Matrix operator -(Matrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return rightSide.Negate(); } /// /// Multiplies a Matrix by a constant and returns the result. /// /// The matrix to multiply. /// The constant to multiply the matrix by. /// The result of the multiplication. /// If is . public static Matrix operator *(Matrix leftSide, T rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } return leftSide.Multiply(rightSide); } /// /// Multiplies a Matrix by a constant and returns the result. /// /// The matrix to multiply. /// The constant to multiply the matrix by. /// The result of the multiplication. /// If is . public static Matrix operator *(T leftSide, Matrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return rightSide.Multiply(leftSide); } /// /// Multiplies two matrices. /// /// This operator will allocate new memory for the result. It will /// choose the representation of either or depending on which /// is denser. /// The left matrix to multiply. /// The right matrix to multiply. /// The result of multiplication. /// If or is . /// If the dimensions of or don't conform. public static Matrix operator *(Matrix leftSide, Matrix rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } if (rightSide == null) { throw new ArgumentNullException("rightSide"); } if (leftSide.ColumnCount != rightSide.RowCount) { throw DimensionsDontMatch(leftSide, rightSide); } return leftSide.Multiply(rightSide); } /// /// Multiplies a Matrix and a Vector. /// /// The matrix to multiply. /// The vector to multiply. /// The result of multiplication. /// If or is . public static Vector operator *(Matrix leftSide, Vector rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } return leftSide.Multiply(rightSide); } /// /// Multiplies a Vector and a Matrix. /// /// The vector to multiply. /// The matrix to multiply. /// The result of multiplication. /// If or is . public static Vector operator *(Vector leftSide, Matrix rightSide) { if (rightSide == null) { throw new ArgumentNullException("rightSide"); } return rightSide.LeftMultiply(leftSide); } /// /// Pointwise multiplies this matrix with another matrix. /// /// The matrix to pointwise multiply with this one. /// If the other matrix is . /// If this matrix and are not the same size. /// A new matrix that is the pointwise multiplication of this matrix and . public virtual Matrix PointwiseMultiply(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, "other"); } var result = CreateMatrix(RowCount, ColumnCount); PointwiseMultiply(other, result); return result; } /// /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. /// /// The matrix to pointwise multiply with this one. /// The matrix to store the result of the pointwise multiplication. /// If the other matrix is . /// If the result matrix is . /// If this matrix and are not the same size. /// If this matrix and are not the same size. public virtual void PointwiseMultiply(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } DoPointwiseMultiply(other, result); } /// /// Pointwise divide this matrix by another matrix. /// /// The matrix to pointwise subtract this one by. /// If the other matrix is . /// If this matrix and are not the same size. /// A new matrix that is the pointwise division of this matrix and . public virtual Matrix PointwiseDivide(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = CreateMatrix(RowCount, ColumnCount); PointwiseDivide(other, result); return result; } /// /// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix. /// /// The matrix to pointwise multiply with this one. /// The matrix to store the result of the pointwise multiplication. protected abstract void DoPointwiseMultiply(Matrix other, Matrix result); /// /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. /// /// The matrix to pointwise divide this one by. /// The matrix to store the result of the pointwise division. /// If the other matrix is . /// If the result matrix is . /// If this matrix and are not the same size. /// If this matrix and are not the same size. public virtual void PointwiseDivide(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } DoPointwiseDivide(other, result); } /// /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. /// /// The matrix to pointwise divide this one by. /// The matrix to store the result of the pointwise division. protected abstract void DoPointwiseDivide(Matrix other, Matrix result); /// /// Computes the modulus for each element of the matrix. /// /// The divisor to use. /// A matrix containing the results. public Matrix Modulus(T divisor) { var result = CreateMatrix(RowCount, ColumnCount); DoModulus(divisor, result); return result; } /// /// Computes the modulus for each element of the matrix. /// /// The divisor to use. /// Matrix to store the results in. public void Modulus(T divisor, Matrix result) { if (result == null) { throw new ArgumentNullException("result"); } if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoModulus(divisor, result); } /// /// Computes the modulus for each element of the matrix. /// /// The divisor to use. /// Matrix to store the results in. protected abstract void DoModulus(T divisor, Matrix result); /// /// Multiplies a Matrix by a constant and returns the result. /// /// The matrix to multiply. /// The constant to multiply the matrix by. /// The result of the multiplication. /// If is . public static Matrix operator %(Matrix leftSide, T rightSide) { if (leftSide == null) { throw new ArgumentNullException("leftSide"); } return leftSide.Modulus(rightSide); } /// /// Computes the trace of this matrix. /// /// The trace of this matrix /// If the matrix is not square public abstract T Trace(); /// /// Calculates the rank of the matrix /// /// effective numerical rank, obtained from SVD public virtual int Rank() { return Svd.Create(this, false).Rank; } /// Calculates the condition number of this matrix. /// The condition number of the matrix. /// The condition number is calculated using singular value decomposition. public virtual T ConditionNumber() { return Svd.Create(this, false).ConditionNumber; } /// Computes the determinant of this matrix. /// The determinant of this matrix. public virtual T Determinant() { if (RowCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } return LU.Create(this).Determinant; } /// Computes the inverse of this matrix. /// The inverse of this matrix. public virtual Matrix Inverse() { if (RowCount != ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare); } return LU.Create(this).Inverse(); } /// /// Computes the Kronecker product of this matrix with the given matrix. The new matrix is M-by-N /// with M = this.Rows * lower.Rows and N = this.Columns * lower.Columns. /// /// The other matrix. /// If other is . /// The kronecker product of the two matrices. public virtual Matrix KroneckerProduct(Matrix other) { if (other == null) { throw new ArgumentNullException("other"); } var result = CreateMatrix(RowCount * other.RowCount, ColumnCount * other.ColumnCount); KroneckerProduct(other, result); return result; } /// /// Computes the Kronecker product of this matrix with the given matrix. The new matrix is M-by-N /// with M = this.Rows * lower.Rows and N = this.Columns * lower.Columns. /// /// The other matrix. /// The kronecker product of the two matrices. /// If other is . /// If the result matrix is . /// If the result matrix's dimensions are not (this.Rows * lower.rows) x (this.Columns * lower.Columns). public virtual void KroneckerProduct(Matrix other, Matrix result) { if (other == null) { throw new ArgumentNullException("other"); } if (result == null) { throw new ArgumentNullException("result"); } if (result.RowCount != (RowCount * other.RowCount) || result.ColumnCount != (ColumnCount * other.ColumnCount)) { throw DimensionsDontMatch(this, other, result); } for (var j = 0; j < ColumnCount; j++) { for (var i = 0; i < RowCount; i++) { result.SetSubMatrix(i * other.RowCount, other.RowCount, j * other.ColumnCount, other.ColumnCount, At(i, j) * other); } } } /// /// Normalizes the columns of a matrix. /// /// The norm under which to normalize the columns under. /// A normalized version of the matrix. /// If the parameter p is not positive. public virtual Matrix NormalizeColumns(int p) { if (p < 1) { throw new ArgumentOutOfRangeException("p", Resources.ArgumentMustBePositive); } var ret = Clone(); for (var index = 0; index < ColumnCount; index++) { ret.SetColumn(index, Column(index).Normalize(p)); } return ret; } /// /// Normalizes the rows of a matrix. /// /// The norm under which to normalize the rows under. /// A normalized version of the matrix. /// If the parameter p is not positive. public virtual Matrix NormalizeRows(int p) { if (p < 1) { throw new ArgumentOutOfRangeException("p", Resources.ArgumentMustBePositive); } var ret = Clone(); for (var index = 0; index < RowCount; index++) { ret.SetRow(index, Row(index).Normalize(p)); } return ret; } #region Exceptions - possibly move elsewhere? public static Exception DimensionsDontMatch(Matrix left, Matrix right, Matrix result, string paramName = null) where TException : Exception { var message = string.Format(Resources.ArgumentMatrixDimensions3, left.RowCount + "x" + left.ColumnCount, right.RowCount + "x" + right.ColumnCount, result.RowCount + "x" + result.ColumnCount); return CreateException(message, paramName); } public static Exception DimensionsDontMatch(Matrix left, Matrix right, string paramName = null) where TException : Exception { var message = string.Format(Resources.ArgumentMatrixDimensions2, left.RowCount + "x" + left.ColumnCount, right.RowCount + "x" + right.ColumnCount); return CreateException(message, paramName); } public static Exception DimensionsDontMatch(Matrix matrix) where TException : Exception { var message = string.Format(Resources.ArgumentMatrixDimensions1, matrix.RowCount + "x" + matrix.ColumnCount); return CreateException(message); } public static Exception DimensionsDontMatch(Matrix left, Vector right, Vector result, string paramName = null) where TException : Exception { return DimensionsDontMatch(left, right.ToColumnMatrix(), result.ToColumnMatrix(), paramName); } public static Exception DimensionsDontMatch(Matrix left, Vector right, string paramName = null) where TException : Exception { return DimensionsDontMatch(left, right.ToColumnMatrix(), paramName); } public static Exception DimensionsDontMatch(Vector left, Matrix right, string paramName = null) where TException : Exception { return DimensionsDontMatch(left.ToColumnMatrix(), right, paramName); } public static Exception DimensionsDontMatch(Vector left, Vector right, string paramName = null) where TException : Exception { return DimensionsDontMatch(left.ToColumnMatrix(), right.ToColumnMatrix(), paramName); } private static Exception CreateException(string message, string paramName = null) where TException : Exception { if (typeof(TException) == typeof(ArgumentException)) { return new ArgumentException(message, paramName); } if (typeof(TException) == typeof(ArgumentOutOfRangeException)) { return new ArgumentOutOfRangeException(paramName, message); } return new Exception(message); } #endregion } }