// // Math.NET Numerics, part of the Math.NET Project // http://numerics.mathdotnet.com // http://github.com/mathnet/mathnet-numerics // // Copyright (c) 2009-2016 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. // using System; using System.Linq; namespace IStation.Numerics.LinearAlgebra { /// /// Defines the base class for Matrix classes. /// public abstract partial class Matrix { /// /// The value of 1.0. /// public static readonly T One = BuilderInstance.Matrix.One; /// /// The value of 0.0. /// public static readonly T Zero = BuilderInstance.Matrix.Zero; /// /// 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); /// /// Complex conjugates each element of this matrix and place the results into the result matrix. /// /// The result of the conjugation. protected abstract void DoConjugate(Matrix result); /// /// Add a scalar to each element of the matrix and stores the result in the result vector. /// /// The scalar to add. /// The matrix to store the result of the addition. protected abstract void DoAdd(T scalar, Matrix 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 two matrices don't have the same dimensions. protected abstract void DoAdd(Matrix other, Matrix result); /// /// Subtracts a scalar from each element of the matrix and stores the result in the result matrix. /// /// The scalar to subtract. /// The matrix to store the result of the subtraction. protected abstract void DoSubtract(T scalar, Matrix result); /// /// Subtracts each element of the matrix from a scalar and stores the result in the result matrix. /// /// The scalar to subtract from. /// The matrix to store the result of the subtraction. protected void DoSubtractFrom(T scalar, Matrix result) { DoNegate(result); result.DoAdd(scalar, 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 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 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); /// /// 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 the 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 this matrix with the conjugate 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 DoConjugateTransposeAndMultiply(Matrix other, Matrix 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 conjugate 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 DoConjugateTransposeThisAndMultiply(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. protected abstract void DoTransposeThisAndMultiply(Matrix other, Matrix 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 DoConjugateTransposeThisAndMultiply(Matrix other, Matrix result); /// /// Divides each element of the matrix by a scalar and places results into the result matrix. /// /// The scalar denominator to use. /// The matrix to store the result of the division. protected abstract void DoDivide(T divisor, Matrix result); /// /// Divides a scalar by each element of the matrix and stores the result in the result matrix. /// /// The scalar numerator to use. /// The matrix to store the result of the division. protected abstract void DoDivideByThis(T dividend, Matrix result); /// /// Computes the canonical modulus, where the result has the sign of the divisor, /// for the given divisor each element of the matrix. /// /// The scalar denominator to use. /// Matrix to store the results in. protected abstract void DoModulus(T divisor, Matrix result); /// /// Computes the canonical modulus, where the result has the sign of the divisor, /// for the given dividend for each element of the matrix. /// /// The scalar numerator to use. /// A vector to store the results in. protected abstract void DoModulusByThis(T dividend, Matrix result); /// /// Computes the remainder (% operator), where the result has the sign of the dividend, /// for the given divisor each element of the matrix. /// /// The scalar denominator to use. /// Matrix to store the results in. protected abstract void DoRemainder(T divisor, Matrix result); /// /// Computes the remainder (% operator), where the result has the sign of the dividend, /// for the given dividend for each element of the matrix. /// /// The scalar numerator to use. /// A vector to store the results in. protected abstract void DoRemainderByThis(T dividend, Matrix 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 pointwise denominator matrix to use. /// The matrix to store the result of the pointwise division. protected abstract void DoPointwiseDivide(Matrix divisor, Matrix result); /// /// Pointwise raise this matrix to an exponent and store the result into the result matrix. /// /// The exponent to raise this matrix values to. /// The matrix to store the result of the pointwise power. protected abstract void DoPointwisePower(T exponent, Matrix result); /// /// Pointwise raise this matrix to an exponent matrix and store the result into the result matrix. /// /// The exponent matrix to raise this matrix values to. /// The matrix to store the result of the pointwise power. protected abstract void DoPointwisePower(Matrix exponent, Matrix result); /// /// Pointwise canonical modulus, where the result has the sign of the divisor, /// of this matrix with another matrix and stores the result into the result matrix. /// /// The pointwise denominator matrix to use /// The result of the modulus. protected abstract void DoPointwiseModulus(Matrix divisor, Matrix result); /// /// Pointwise remainder (% operator), where the result has the sign of the dividend, /// of this matrix with another matrix and stores the result into the result matrix. /// /// The pointwise denominator matrix to use /// The result of the modulus. protected abstract void DoPointwiseRemainder(Matrix divisor, Matrix result); /// /// Pointwise applies the exponential function to each value and stores the result into the result matrix. /// /// The matrix to store the result. protected abstract void DoPointwiseExp(Matrix result); /// /// Pointwise applies the natural logarithm function to each value and stores the result into the result matrix. /// /// The matrix to store the result. protected abstract void DoPointwiseLog(Matrix result); protected abstract void DoPointwiseAbs(Matrix result); protected abstract void DoPointwiseAcos(Matrix result); protected abstract void DoPointwiseAsin(Matrix result); protected abstract void DoPointwiseAtan(Matrix result); protected abstract void DoPointwiseCeiling(Matrix result); protected abstract void DoPointwiseCos(Matrix result); protected abstract void DoPointwiseCosh(Matrix result); protected abstract void DoPointwiseFloor(Matrix result); protected abstract void DoPointwiseLog10(Matrix result); protected abstract void DoPointwiseRound(Matrix result); protected abstract void DoPointwiseSign(Matrix result); protected abstract void DoPointwiseSin(Matrix result); protected abstract void DoPointwiseSinh(Matrix result); protected abstract void DoPointwiseSqrt(Matrix result); protected abstract void DoPointwiseTan(Matrix result); protected abstract void DoPointwiseTanh(Matrix result); protected abstract void DoPointwiseAtan2(Matrix other, Matrix result); protected abstract void DoPointwiseMinimum(T scalar, Matrix result); protected abstract void DoPointwiseMinimum(Matrix other, Matrix result); protected abstract void DoPointwiseMaximum(T scalar, Matrix result); protected abstract void DoPointwiseMaximum(Matrix other, Matrix result); protected abstract void DoPointwiseAbsoluteMinimum(T scalar, Matrix result); protected abstract void DoPointwiseAbsoluteMinimum(Matrix other, Matrix result); protected abstract void DoPointwiseAbsoluteMaximum(T scalar, Matrix result); protected abstract void DoPointwiseAbsoluteMaximum(Matrix other, Matrix result); /// /// Adds a scalar to each element of the matrix. /// /// The scalar to add. /// The result of the addition. /// If the two matrices don't have the same dimensions. public Matrix Add(T scalar) { if (scalar.Equals(Zero)) { return Clone(); } var result = Build.SameAs(this); DoAdd(scalar, result); return result; } /// /// Adds a scalar to each element of the matrix and stores the result in the result matrix. /// /// The scalar to add. /// The matrix to store the result of the addition. /// If the two matrices don't have the same dimensions. public void Add(T scalar, Matrix result) { if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } if (scalar.Equals(Zero)) { CopyTo(result); return; } DoAdd(scalar, result); } /// /// Adds another matrix to this matrix. /// /// The matrix to add to this matrix. /// The result of the addition. /// If the two matrices don't have the same dimensions. public Matrix Add(Matrix other) { if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, 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 two matrices don't have the same dimensions. public void Add(Matrix other, Matrix result) { 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); } /// /// Subtracts a scalar from each element of the matrix. /// /// The scalar to subtract. /// A new matrix containing the subtraction of this matrix and the scalar. public Matrix Subtract(T scalar) { if (scalar.Equals(Zero)) { return Clone(); } var result = Build.SameAs(this); DoSubtract(scalar, result); return result; } /// /// Subtracts a scalar from each element of the matrix and stores the result in the result matrix. /// /// The scalar to subtract. /// The matrix to store the result of the subtraction. /// If this matrix and are not the same size. public void Subtract(T scalar, Matrix result) { if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } if (scalar.Equals(Zero)) { CopyTo(result); return; } DoSubtract(scalar, result); } /// /// Subtracts each element of the matrix from a scalar. /// /// The scalar to subtract from. /// A new matrix containing the subtraction of the scalar and this matrix. public Matrix SubtractFrom(T scalar) { var result = Build.SameAs(this); DoSubtractFrom(scalar, result); return result; } /// /// Subtracts each element of the matrix from a scalar and stores the result in the result matrix. /// /// The scalar to subtract from. /// The matrix to store the result of the subtraction. /// If this matrix and are not the same size. public void SubtractFrom(T scalar, Matrix result) { if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } DoSubtractFrom(scalar, result); } /// /// Subtracts another matrix from this matrix. /// /// The matrix to subtract. /// The result of the subtraction. /// If the two matrices don't have the same dimensions. public Matrix Subtract(Matrix other) { if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, 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 two matrices don't have the same dimensions. public void Subtract(Matrix other, Matrix result) { if (other.RowCount != RowCount || other.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, other, "other"); } if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result, "result"); } DoSubtract(other, result); } /// /// Multiplies each element of this matrix with a scalar. /// /// The scalar to multiply with. /// The result of the multiplication. public Matrix Multiply(T scalar) { if (scalar.Equals(One)) { return Clone(); } if (scalar.Equals(Zero)) { return Build.SameAs(this); } var result = Build.SameAs(this); 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's dimensions are not the same as this matrix. public void Multiply(T scalar, Matrix result) { if (result.RowCount != RowCount) { throw new ArgumentException("Matrix row dimensions must agree.", nameof(result)); } if (result.ColumnCount != ColumnCount) { throw new ArgumentException("Matrix column dimensions must agree.", nameof(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 Matrix Divide(T scalar) { if (scalar.Equals(One)) { return Clone(); } if (scalar.Equals(Zero)) { throw new DivideByZeroException(); } var result = Build.SameAs(this); 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's dimensions are not the same as this matrix. public void Divide(T scalar, Matrix result) { if (result.RowCount != RowCount) { throw new ArgumentException("Matrix row dimensions must agree.", nameof(result)); } if (result.ColumnCount != ColumnCount) { throw new ArgumentException("Matrix column dimensions must agree.", nameof(result)); } if (scalar.Equals(One)) { CopyTo(result); return; } if (scalar.Equals(Zero)) { throw new DivideByZeroException(); } DoDivide(scalar, result); } /// /// Divides a scalar by each element of the matrix. /// /// The scalar to divide. /// The result of the division. public Matrix DivideByThis(T scalar) { var result = Build.SameAs(this); DoDivideByThis(scalar, result); return result; } /// /// Divides a scalar by each element of the matrix and places results into the result matrix. /// /// The scalar to divide. /// The matrix to store the result of the division. /// If the result matrix's dimensions are not the same as this matrix. public void DivideByThis(T scalar, Matrix result) { if (result.RowCount != RowCount) { throw new ArgumentException("Matrix row dimensions must agree.", nameof(result)); } if (result.ColumnCount != ColumnCount) { throw new ArgumentException("Matrix column dimensions must agree.", nameof(result)); } DoDivideByThis(scalar, result); } /// /// Multiplies this matrix by a vector and returns the result. /// /// The vector to multiply with. /// The result of the multiplication. /// If this.ColumnCount != rightSide.Count. public Vector Multiply(Vector rightSide) { if (ColumnCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } var ret = Vector.Build.SameAs(this, rightSide, RowCount); DoMultiply(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 result.Count != this.RowCount. /// If this.ColumnCount != .Count. public void Multiply(Vector rightSide, Vector result) { if (ColumnCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } if (RowCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(rightSide, result)) { var tmp = Vector.Build.SameAs(result); DoMultiply(rightSide, tmp); tmp.CopyTo(result); } else { DoMultiply(rightSide, result); } } /// /// Left multiply a matrix with a vector ( = vector * matrix ). /// /// The vector to multiply with. /// The result of the multiplication. /// If this.RowCount != .Count. public Vector LeftMultiply(Vector leftSide) { if (RowCount != leftSide.Count) { throw DimensionsDontMatch(this, leftSide, "leftSide"); } var ret = Vector.Build.SameAs(this, leftSide, ColumnCount); DoLeftMultiply(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 result.Count != this.ColumnCount. /// If this.RowCount != .Count. public void LeftMultiply(Vector leftSide, Vector result) { if (RowCount != leftSide.Count) { throw DimensionsDontMatch(this, leftSide, "leftSide"); } if (ColumnCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(leftSide, result)) { var tmp = Vector.Build.SameAs(result); DoLeftMultiply(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 this.Columns != other.Rows. /// If the result matrix's dimensions are not the this.Rows x other.Columns. public void Multiply(Matrix other, Matrix 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 = Build.SameAs(result); DoMultiply(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. /// The result of the multiplication. public Matrix Multiply(Matrix other) { if (ColumnCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, RowCount, other.ColumnCount); DoMultiply(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. /// If this.Columns != other.ColumnCount. /// If the result matrix's dimensions are not the this.RowCount x other.RowCount. public void TransposeAndMultiply(Matrix other, Matrix 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 = Build.SameAs(result); DoTransposeAndMultiply(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. /// The result of the multiplication. public Matrix TransposeAndMultiply(Matrix other) { if (ColumnCount != other.ColumnCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, RowCount, other.RowCount); DoTransposeAndMultiply(other, result); return 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 this.RowCount != rightSide.Count. public Vector TransposeThisAndMultiply(Vector rightSide) { if (RowCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } var result = Vector.Build.SameAs(this, rightSide, ColumnCount); DoTransposeThisAndMultiply(rightSide, result); return 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. /// If result.Count != this.ColumnCount. /// If this.RowCount != .Count. public void TransposeThisAndMultiply(Vector rightSide, Vector result) { if (RowCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } if (ColumnCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(rightSide, result)) { var tmp = Vector.Build.SameAs(result); DoTransposeThisAndMultiply(rightSide, tmp); tmp.CopyTo(result); } else { DoTransposeThisAndMultiply(rightSide, 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 this.Rows != other.RowCount. /// If the result matrix's dimensions are not the this.ColumnCount x other.ColumnCount. public void TransposeThisAndMultiply(Matrix other, Matrix 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 = Build.SameAs(result); DoTransposeThisAndMultiply(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. /// The result of the multiplication. public Matrix TransposeThisAndMultiply(Matrix other) { if (RowCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, ColumnCount, other.ColumnCount); DoTransposeThisAndMultiply(other, result); return result; } /// /// Multiplies this matrix with the conjugate transpose of another matrix and places the results into the result matrix. /// /// The matrix to multiply with. /// The result of the multiplication. /// If this.Columns != other.ColumnCount. /// If the result matrix's dimensions are not the this.RowCount x other.RowCount. public void ConjugateTransposeAndMultiply(Matrix other, Matrix 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 = Build.SameAs(result); DoConjugateTransposeAndMultiply(other, tmp); tmp.CopyTo(result); } else { DoConjugateTransposeAndMultiply(other, result); } } /// /// Multiplies this matrix with the conjugate transpose of another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Columns != other.ColumnCount. /// The result of the multiplication. public Matrix ConjugateTransposeAndMultiply(Matrix other) { if (ColumnCount != other.ColumnCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, RowCount, other.RowCount); DoConjugateTransposeAndMultiply(other, result); return result; } /// /// Multiplies the conjugate transpose of this matrix by a vector and returns the result. /// /// The vector to multiply with. /// The result of the multiplication. /// If this.RowCount != rightSide.Count. public Vector ConjugateTransposeThisAndMultiply(Vector rightSide) { if (RowCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } var result = Vector.Build.SameAs(this, rightSide, ColumnCount); DoConjugateTransposeThisAndMultiply(rightSide, result); return result; } /// /// Multiplies the conjugate 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 result.Count != this.ColumnCount. /// If this.RowCount != .Count. public void ConjugateTransposeThisAndMultiply(Vector rightSide, Vector result) { if (RowCount != rightSide.Count) { throw DimensionsDontMatch(this, rightSide, "rightSide"); } if (ColumnCount != result.Count) { throw DimensionsDontMatch(this, result, "result"); } if (ReferenceEquals(rightSide, result)) { var tmp = Vector.Build.SameAs(result); DoConjugateTransposeThisAndMultiply(rightSide, tmp); tmp.CopyTo(result); } else { DoConjugateTransposeThisAndMultiply(rightSide, result); } } /// /// Multiplies the conjugate 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 this.Rows != other.RowCount. /// If the result matrix's dimensions are not the this.ColumnCount x other.ColumnCount. public void ConjugateTransposeThisAndMultiply(Matrix other, Matrix 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 = Build.SameAs(result); DoConjugateTransposeThisAndMultiply(other, tmp); tmp.CopyTo(result); } else { DoConjugateTransposeThisAndMultiply(other, result); } } /// /// Multiplies the conjugate transpose of this matrix with another matrix and returns the result. /// /// The matrix to multiply with. /// If this.Rows != other.RowCount. /// The result of the multiplication. public Matrix ConjugateTransposeThisAndMultiply(Matrix other) { if (RowCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other, ColumnCount, other.ColumnCount); DoConjugateTransposeThisAndMultiply(other, result); return result; } private static Matrix IntPower(int exponent, Matrix x, Matrix y, Matrix work) { // We try to be smart about not allocating more matrices than needed // and to minimize the number of multiplications (not optimal on either though) // TODO: For large or non-integer exponents we could diagonalize the matrix with // a similarity transform (eigenvalue decomposition) // return y*x if (exponent == 1) { // return x if (y == null) { return x; } if (work == null) work = y.Multiply(x); else y.Multiply(x, work); return work; } // return y*x^2 if (exponent == 2) { if (work == null) work = x.Multiply(x); else x.Multiply(x, work); // return x^2 if (y == null) { return work; } y.Multiply(work, x); return x; } // recursive n <-- n/2, y <-- y, x <-- x^2 if (exponent.IsEven()) { // we store the new x in work, keep the y as is and reuse the old x as new work matrix. if (work == null) work = x.Multiply(x); else x.Multiply(x, work); return IntPower(exponent/2, work, y, x); } // recursive n <-- (n-1)/2, y <-- x, x <-- x^2 if (y == null) { // we store the new x in work, directly use the old x as y. no work matrix. if (work == null) work = x.Multiply(x); else x.Multiply(x, work); return IntPower((exponent - 1)/2, work, x, null); } // recursive n <-- (n-1)/2, y <-- y*x, x <-- x^2 // we store the new y in work, the new x in y, and reuse the old x as work if (work == null) work = y.Multiply(x); else y.Multiply(x, work); x.Multiply(x, y); return IntPower((exponent - 1)/2, y, work, x); } /// /// Raises this square matrix to a positive integer exponent and places the results into the result matrix. /// /// The positive integer exponent to raise the matrix to. /// The result of the power. public void Power(int exponent, Matrix result) { if (RowCount != ColumnCount || result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result); } if (exponent < 0) { throw new ArgumentException("Value must not be negative (zero is ok)."); } if (exponent == 0) { Build.DiagonalIdentity(RowCount, ColumnCount).CopyTo(result); return; } if (exponent == 1) { CopyTo(result); return; } if (exponent == 2) { Multiply(this, result); return; } var res = IntPower(exponent, Clone(), null, result); if (!ReferenceEquals(res, result)) { res.CopyTo(result); } } /// /// Multiplies this square matrix with another matrix and returns the result. /// /// The positive integer exponent to raise the matrix to. public Matrix Power(int exponent) { if (RowCount != ColumnCount) throw new ArgumentException("Matrix must be square."); if (exponent < 0) throw new ArgumentException("Value must not be negative (zero is ok)."); if (exponent == 0) return Build.DiagonalIdentity(RowCount, ColumnCount); if (exponent == 1) return this; if (exponent == 2) return Multiply(this); return IntPower(exponent, Clone(), null, null); } /// /// Negate each element of this matrix. /// /// A matrix containing the negated values. public Matrix Negate() { var result = Build.SameAs(this); 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's dimensions are not the same as this matrix. public void Negate(Matrix result) { if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result); } DoNegate(result); } /// /// Complex conjugate each element of this matrix. /// /// A matrix containing the conjugated values. public Matrix Conjugate() { var result = Build.SameAs(this); DoConjugate(result); return result; } /// /// Complex conjugate each element of this matrix and place the results into the result matrix. /// /// The result of the conjugation. /// if the result matrix's dimensions are not the same as this matrix. public void Conjugate(Matrix result) { if (result.RowCount != RowCount || result.ColumnCount != ColumnCount) { throw DimensionsDontMatch(this, result); } DoConjugate(result); } /// /// Computes the canonical modulus, where the result has the sign of the divisor, /// for each element of the matrix. /// /// The scalar denominator to use. /// A matrix containing the results. public Matrix Modulus(T divisor) { var result = Build.SameAs(this); DoModulus(divisor, result); return result; } /// /// Computes the canonical modulus, where the result has the sign of the divisor, /// for each element of the matrix. /// /// The scalar denominator to use. /// Matrix to store the results in. public void Modulus(T divisor, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoModulus(divisor, result); } /// /// Computes the canonical modulus, where the result has the sign of the divisor, /// for each element of the matrix. /// /// The scalar numerator to use. /// A matrix containing the results. public Matrix ModulusByThis(T dividend) { var result = Build.SameAs(this); DoModulusByThis(dividend, result); return result; } /// /// Computes the canonical modulus, where the result has the sign of the divisor, /// for each element of the matrix. /// /// The scalar numerator to use. /// Matrix to store the results in. public void ModulusByThis(T dividend, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoModulusByThis(dividend, result); } /// /// Computes the remainder (matrix % divisor), where the result has the sign of the dividend, /// for each element of the matrix. /// /// The scalar denominator to use. /// A matrix containing the results. public Matrix Remainder(T divisor) { var result = Build.SameAs(this); DoRemainder(divisor, result); return result; } /// /// Computes the remainder (matrix % divisor), where the result has the sign of the dividend, /// for each element of the matrix. /// /// The scalar denominator to use. /// Matrix to store the results in. public void Remainder(T divisor, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoRemainder(divisor, result); } /// /// Computes the remainder (dividend % matrix), where the result has the sign of the dividend, /// for each element of the matrix. /// /// The scalar numerator to use. /// A matrix containing the results. public Matrix RemainderByThis(T dividend) { var result = Build.SameAs(this); DoRemainderByThis(dividend, result); return result; } /// /// Computes the remainder (dividend % matrix), where the result has the sign of the dividend, /// for each element of the matrix. /// /// The scalar numerator to use. /// Matrix to store the results in. public void RemainderByThis(T dividend, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoRemainderByThis(dividend, result); } /// /// Pointwise multiplies this matrix with another matrix. /// /// The matrix to pointwise multiply with this one. /// If this matrix and are not the same size. /// A new matrix that is the pointwise multiplication of this matrix and . public Matrix PointwiseMultiply(Matrix other) { if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, "other"); } var result = Build.SameAs(this, other); DoPointwiseMultiply(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 this matrix and are not the same size. /// If this matrix and are not the same size. public void PointwiseMultiply(Matrix other, Matrix 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 pointwise denominator matrix to use. /// If this matrix and are not the same size. /// A new matrix that is the pointwise division of this matrix and . public Matrix PointwiseDivide(Matrix divisor) { if (ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount) { throw DimensionsDontMatch(this, divisor); } var result = Build.SameAs(this, divisor); DoPointwiseDivide(divisor, result); return result; } /// /// Pointwise divide this matrix by another matrix and stores the result into the result matrix. /// /// The pointwise denominator matrix to use. /// The matrix to store the result of the pointwise division. /// If this matrix and are not the same size. /// If this matrix and are not the same size. public void PointwiseDivide(Matrix divisor, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount) { throw DimensionsDontMatch(this, divisor, result); } DoPointwiseDivide(divisor, result); } /// /// Pointwise raise this matrix to an exponent and store the result into the result matrix. /// /// The exponent to raise this matrix values to. public Matrix PointwisePower(T exponent) { var result = Build.SameAs(this); DoPointwisePower(exponent, result); return result; } /// /// Pointwise raise this matrix to an exponent. /// /// The exponent to raise this matrix values to. /// The matrix to store the result into. /// If this matrix and are not the same size. public void PointwisePower(T exponent, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoPointwisePower(exponent, result); } /// /// Pointwise raise this matrix to an exponent and store the result into the result matrix. /// /// The exponent to raise this matrix values to. public Matrix PointwisePower(Matrix exponent) { if (ColumnCount != exponent.ColumnCount || RowCount != exponent.RowCount) { throw DimensionsDontMatch(this, exponent); } var result = Build.SameAs(this); DoPointwisePower(exponent, result); return result; } /// /// Pointwise raise this matrix to an exponent. /// /// The exponent to raise this matrix values to. /// The matrix to store the result into. /// If this matrix and are not the same size. public void PointwisePower(Matrix exponent, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != exponent.ColumnCount || RowCount != exponent.RowCount) { throw DimensionsDontMatch(this, exponent, result); } DoPointwisePower(exponent, result); } /// /// Pointwise canonical modulus, where the result has the sign of the divisor, /// of this matrix by another matrix. /// /// The pointwise denominator matrix to use. /// If this matrix and are not the same size. public Matrix PointwiseModulus(Matrix divisor) { if (ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount) { throw DimensionsDontMatch(this, divisor); } var result = Build.SameAs(this, divisor); DoPointwiseModulus(divisor, result); return result; } /// /// Pointwise canonical modulus, where the result has the sign of the divisor, /// of this matrix by another matrix and stores the result into the result matrix. /// /// The pointwise denominator matrix to use. /// The matrix to store the result of the pointwise modulus. /// If this matrix and are not the same size. /// If this matrix and are not the same size. public void PointwiseModulus(Matrix divisor, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount) { throw DimensionsDontMatch(this, divisor, result); } DoPointwiseModulus(divisor, result); } /// /// Pointwise remainder (% operator), where the result has the sign of the dividend, /// of this matrix by another matrix. /// /// The pointwise denominator matrix to use. /// If this matrix and are not the same size. public Matrix PointwiseRemainder(Matrix divisor) { if (ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount) { throw DimensionsDontMatch(this, divisor); } var result = Build.SameAs(this, divisor); DoPointwiseRemainder(divisor, result); return result; } /// /// Pointwise remainder (% operator), where the result has the sign of the dividend, /// of this matrix by another matrix and stores the result into the result matrix. /// /// The pointwise denominator matrix to use. /// The matrix to store the result of the pointwise remainder. /// If this matrix and are not the same size. /// If this matrix and are not the same size. public void PointwiseRemainder(Matrix divisor, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount) { throw DimensionsDontMatch(this, divisor, result); } DoPointwiseRemainder(divisor, result); } /// /// Helper function to apply a unary function to a matrix. The function /// f modifies the matrix given to it in place. Before its /// called, a copy of the 'this' matrix is first created, then passed to /// f. The copy is then returned as the result /// /// Function which takes a matrix, modifies it in place and returns void /// New instance of matrix which is the result protected Matrix PointwiseUnary(Action> f) { var result = Build.SameAs(this); f(result); return result; } /// /// Helper function to apply a unary function which modifies a matrix /// in place. /// /// Function which takes a matrix, modifies it in place and returns void /// The matrix to be passed to f and where the result is to be stored /// If this vector and are not the same size. protected void PointwiseUnary(Action> f, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } f(result); } /// /// Helper function to apply a binary function which takes two matrices /// and modifies the latter in place. A copy of the "this" matrix is /// first made and then passed to f together with the other matrix. The /// copy is then returned as the result /// /// Function which takes two matrices, modifies the second in place and returns void /// The other matrix to be passed to the function as argument. It is not modified /// The resulting matrix /// If this matrix and are not the same dimension. protected Matrix PointwiseBinary(Action, Matrix> f, Matrix other) { if (ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other); } var result = Build.SameAs(this, other); f(other, result); return result; } /// /// Helper function to apply a binary function which takes two matrices /// and modifies the second one in place /// /// Function which takes two matrices, modifies the second in place and returns void /// The other matrix to be passed to the function as argument. It is not modified /// The matrix to store the result. /// The resulting matrix /// If this matrix and are not the same dimension. protected void PointwiseBinary(Action,Matrix> f, Matrix other, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } f(other, result); } /// /// Pointwise applies the exponent function to each value. /// public Matrix PointwiseExp() { return PointwiseUnary(DoPointwiseExp); } /// /// Pointwise applies the exponent function to each value. /// /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseExp(Matrix result) { PointwiseUnary(DoPointwiseExp, result); } /// /// Pointwise applies the natural logarithm function to each value. /// public Matrix PointwiseLog() { return PointwiseUnary(DoPointwiseLog); } /// /// Pointwise applies the natural logarithm function to each value. /// /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseLog(Matrix result) { PointwiseUnary(DoPointwiseLog, result); } /// /// Pointwise applies the abs function to each value /// public Matrix PointwiseAbs() { return PointwiseUnary(DoPointwiseAbs); } /// /// Pointwise applies the abs function to each value /// /// The vector to store the result public void PointwiseAbs(Matrix result) { PointwiseUnary(DoPointwiseAbs, result); } /// /// Pointwise applies the acos function to each value /// public Matrix PointwiseAcos() { return PointwiseUnary(DoPointwiseAcos); } /// /// Pointwise applies the acos function to each value /// /// The vector to store the result public void PointwiseAcos(Matrix result) { PointwiseUnary(DoPointwiseAcos, result); } /// /// Pointwise applies the asin function to each value /// public Matrix PointwiseAsin() { return PointwiseUnary(DoPointwiseAsin); } /// /// Pointwise applies the asin function to each value /// /// The vector to store the result public void PointwiseAsin(Matrix result) { PointwiseUnary(DoPointwiseAsin, result); } /// /// Pointwise applies the atan function to each value /// public Matrix PointwiseAtan() { return PointwiseUnary(DoPointwiseAtan); } /// /// Pointwise applies the atan function to each value /// /// The vector to store the result public void PointwiseAtan(Matrix result) { PointwiseUnary(DoPointwiseAtan, result); } /// /// Pointwise applies the atan2 function to each value of the current /// matrix and a given other matrix being the 'x' of atan2 and the /// 'this' matrix being the 'y' /// /// /// public Matrix PointwiseAtan2(Matrix other) { return PointwiseBinary(DoPointwiseAtan2, other); } /// /// Pointwise applies the atan2 function to each value of the current /// matrix and a given other matrix being the 'x' of atan2 and the /// 'this' matrix being the 'y' /// /// The other matrix 'y' /// The matrix with the result and 'x' /// public void PointwiseAtan2(Matrix other, Matrix result) { PointwiseBinary(DoPointwiseAtan2, other, result); } /// /// Pointwise applies the ceiling function to each value /// public Matrix PointwiseCeiling() { return PointwiseUnary(DoPointwiseCeiling); } /// /// Pointwise applies the ceiling function to each value /// /// The vector to store the result public void PointwiseCeiling(Matrix result) { PointwiseUnary(DoPointwiseCeiling, result); } /// /// Pointwise applies the cos function to each value /// public Matrix PointwiseCos() { return PointwiseUnary(DoPointwiseCos); } /// /// Pointwise applies the cos function to each value /// /// The vector to store the result public void PointwiseCos(Matrix result) { PointwiseUnary(DoPointwiseCos, result); } /// /// Pointwise applies the cosh function to each value /// public Matrix PointwiseCosh() { return PointwiseUnary(DoPointwiseCosh); } /// /// Pointwise applies the cosh function to each value /// /// The vector to store the result public void PointwiseCosh(Matrix result) { PointwiseUnary(DoPointwiseCosh, result); } /// /// Pointwise applies the floor function to each value /// public Matrix PointwiseFloor() { return PointwiseUnary(DoPointwiseFloor); } /// /// Pointwise applies the floor function to each value /// /// The vector to store the result public void PointwiseFloor(Matrix result) { PointwiseUnary(DoPointwiseFloor, result); } /// /// Pointwise applies the log10 function to each value /// public Matrix PointwiseLog10() { return PointwiseUnary(DoPointwiseLog10); } /// /// Pointwise applies the log10 function to each value /// /// The vector to store the result public void PointwiseLog10(Matrix result) { PointwiseUnary(DoPointwiseLog10, result); } /// /// Pointwise applies the round function to each value /// public Matrix PointwiseRound() { return PointwiseUnary(DoPointwiseRound); } /// /// Pointwise applies the round function to each value /// /// The vector to store the result public void PointwiseRound(Matrix result) { PointwiseUnary(DoPointwiseRound, result); } /// /// Pointwise applies the sign function to each value /// public Matrix PointwiseSign() { return PointwiseUnary(DoPointwiseSign); } /// /// Pointwise applies the sign function to each value /// /// The vector to store the result public void PointwiseSign(Matrix result) { PointwiseUnary(DoPointwiseSign, result); } /// /// Pointwise applies the sin function to each value /// public Matrix PointwiseSin() { return PointwiseUnary(DoPointwiseSin); } /// /// Pointwise applies the sin function to each value /// /// The vector to store the result public void PointwiseSin(Matrix result) { PointwiseUnary(DoPointwiseSin, result); } /// /// Pointwise applies the sinh function to each value /// public Matrix PointwiseSinh() { return PointwiseUnary(DoPointwiseSinh); } /// /// Pointwise applies the sinh function to each value /// /// The vector to store the result public void PointwiseSinh(Matrix result) { PointwiseUnary(DoPointwiseSinh, result); } /// /// Pointwise applies the sqrt function to each value /// public Matrix PointwiseSqrt() { return PointwiseUnary(DoPointwiseSqrt); } /// /// Pointwise applies the sqrt function to each value /// /// The vector to store the result public void PointwiseSqrt(Matrix result) { PointwiseUnary(DoPointwiseSqrt, result); } /// /// Pointwise applies the tan function to each value /// public Matrix PointwiseTan() { return PointwiseUnary(DoPointwiseTan); } /// /// Pointwise applies the tan function to each value /// /// The vector to store the result public void PointwiseTan(Matrix result) { PointwiseUnary(DoPointwiseTan, result); } /// /// Pointwise applies the tanh function to each value /// public Matrix PointwiseTanh() { return PointwiseUnary(DoPointwiseTanh); } /// /// Pointwise applies the tanh function to each value /// /// The vector to store the result public void PointwiseTanh(Matrix result) { PointwiseUnary(DoPointwiseTanh, result); } /// /// 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(false).Rank; } /// /// Calculates the nullity of the matrix. /// /// effective numerical nullity, obtained from SVD public int Nullity() { return ColumnCount - 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(false).ConditionNumber; } /// Computes the determinant of this matrix. /// The determinant of this matrix. public virtual T Determinant() { if (RowCount != ColumnCount) { throw new ArgumentException("Matrix must be square."); } return LU().Determinant; } /// /// Computes an orthonormal basis for the null space of this matrix, /// also known as the kernel of the corresponding matrix transformation. /// public virtual Vector[] Kernel() { var svd = Svd(true); return svd.VT.EnumerateRows(svd.Rank, ColumnCount - svd.Rank).ToArray(); } /// /// Computes an orthonormal basis for the column space of this matrix, /// also known as the range or image of the corresponding matrix transformation. /// public virtual Vector[] Range() { var svd = Svd(true); return svd.U.EnumerateColumns(0, svd.Rank).ToArray(); } /// Computes the inverse of this matrix. /// The inverse of this matrix. public virtual Matrix Inverse() { if (RowCount != ColumnCount) { throw new ArgumentException("Matrix must be square."); } return LU().Inverse(); } /// Computes the Moore-Penrose Pseudo-Inverse of this matrix. public abstract Matrix PseudoInverse(); /// /// 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. public Matrix KroneckerProduct(Matrix other) { var result = Build.SameAs(this, other, 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 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 (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); } } } /// /// Pointwise applies the minimum with a scalar to each value. /// /// The scalar value to compare to. public Matrix PointwiseMinimum(T scalar) { var result = Build.SameAs(this); DoPointwiseMinimum(scalar, result); return result; } /// /// Pointwise applies the minimum with a scalar to each value. /// /// The scalar value to compare to. /// The vector to store the result. /// If this vector and are not the same size. public void PointwiseMinimum(T scalar, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoPointwiseMinimum(scalar, result); } /// /// Pointwise applies the maximum with a scalar to each value. /// /// The scalar value to compare to. public Matrix PointwiseMaximum(T scalar) { var result = Build.SameAs(this); DoPointwiseMaximum(scalar, result); return result; } /// /// Pointwise applies the maximum with a scalar to each value. /// /// The scalar value to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseMaximum(T scalar, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoPointwiseMaximum(scalar, result); } /// /// Pointwise applies the absolute minimum with a scalar to each value. /// /// The scalar value to compare to. public Matrix PointwiseAbsoluteMinimum(T scalar) { var result = Build.SameAs(this); DoPointwiseAbsoluteMinimum(scalar, result); return result; } /// /// Pointwise applies the absolute minimum with a scalar to each value. /// /// The scalar value to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseAbsoluteMinimum(T scalar, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoPointwiseAbsoluteMinimum(scalar, result); } /// /// Pointwise applies the absolute maximum with a scalar to each value. /// /// The scalar value to compare to. public Matrix PointwiseAbsoluteMaximum(T scalar) { var result = Build.SameAs(this); DoPointwiseAbsoluteMaximum(scalar, result); return result; } /// /// Pointwise applies the absolute maximum with a scalar to each value. /// /// The scalar value to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseAbsoluteMaximum(T scalar, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount) { throw DimensionsDontMatch(this, result); } DoPointwiseAbsoluteMaximum(scalar, result); } /// /// Pointwise applies the minimum with the values of another matrix to each value. /// /// The matrix with the values to compare to. public Matrix PointwiseMinimum(Matrix other) { var result = Build.SameAs(this); DoPointwiseMinimum(other, result); return result; } /// /// Pointwise applies the minimum with the values of another matrix to each value. /// /// The matrix with the values to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseMinimum(Matrix other, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } DoPointwiseMinimum(other, result); } /// /// Pointwise applies the maximum with the values of another matrix to each value. /// /// The matrix with the values to compare to. public Matrix PointwiseMaximum(Matrix other) { var result = Build.SameAs(this); DoPointwiseMaximum(other, result); return result; } /// /// Pointwise applies the maximum with the values of another matrix to each value. /// /// The matrix with the values to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseMaximum(Matrix other, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } DoPointwiseMaximum(other, result); } /// /// Pointwise applies the absolute minimum with the values of another matrix to each value. /// /// The matrix with the values to compare to. public Matrix PointwiseAbsoluteMinimum(Matrix other) { var result = Build.SameAs(this); DoPointwiseAbsoluteMinimum(other, result); return result; } /// /// Pointwise applies the absolute minimum with the values of another matrix to each value. /// /// The matrix with the values to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseAbsoluteMinimum(Matrix other, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } DoPointwiseAbsoluteMinimum(other, result); } /// /// Pointwise applies the absolute maximum with the values of another matrix to each value. /// /// The matrix with the values to compare to. public Matrix PointwiseAbsoluteMaximum(Matrix other) { var result = Build.SameAs(this); DoPointwiseAbsoluteMaximum(other, result); return result; } /// /// Pointwise applies the absolute maximum with the values of another matrix to each value. /// /// The matrix with the values to compare to. /// The matrix to store the result. /// If this matrix and are not the same size. public void PointwiseAbsoluteMaximum(Matrix other, Matrix result) { if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount) { throw DimensionsDontMatch(this, other, result); } DoPointwiseAbsoluteMaximum(other, result); } /// Calculates the induced L1 norm of this matrix. /// The maximum absolute column sum of the matrix. public abstract double L1Norm(); /// Calculates the induced L2 norm of the matrix. /// The largest singular value of the matrix. /// /// For sparse matrices, the L2 norm is computed using a dense implementation of singular value decomposition. /// In a later release, it will be replaced with a sparse implementation. /// public virtual double L2Norm() { return Svd(false).L2Norm; } /// Calculates the induced infinity norm of this matrix. /// The maximum absolute row sum of the matrix. public abstract double InfinityNorm(); /// Calculates the entry-wise Frobenius norm of this matrix. /// The square root of the sum of the squared values. public abstract double FrobeniusNorm(); /// /// Calculates the p-norms of all row vectors. /// Typical values for p are 1.0 (L1, Manhattan norm), 2.0 (L2, Euclidean norm) and positive infinity (infinity norm) /// public abstract Vector RowNorms(double norm); /// /// Calculates the p-norms of all column vectors. /// Typical values for p are 1.0 (L1, Manhattan norm), 2.0 (L2, Euclidean norm) and positive infinity (infinity norm) /// public abstract Vector ColumnNorms(double norm); /// /// Normalizes all row vectors to a unit p-norm. /// Typical values for p are 1.0 (L1, Manhattan norm), 2.0 (L2, Euclidean norm) and positive infinity (infinity norm) /// public abstract Matrix NormalizeRows(double norm); /// /// Normalizes all column vectors to a unit p-norm. /// Typical values for p are 1.0 (L1, Manhattan norm), 2.0 (L2, Euclidean norm) and positive infinity (infinity norm) /// public abstract Matrix NormalizeColumns(double norm); /// /// Calculates the value sum of each row vector. /// public abstract Vector RowSums(); /// /// Calculates the value sum of each column vector. /// public abstract Vector ColumnSums(); /// /// Calculates the absolute value sum of each row vector. /// public abstract Vector RowAbsoluteSums(); /// /// Calculates the absolute value sum of each column vector. /// public abstract Vector ColumnAbsoluteSums(); #region Exceptions - possibly move elsewhere? internal static Exception DimensionsDontMatch(Matrix left, Matrix right, Matrix result, string paramName = null) where TException : Exception { var message = $"Matrix dimensions must agree: op1 is {left.RowCount}x{left.ColumnCount}, op2 is {right.RowCount}x{right.ColumnCount}, op3 is {result.RowCount}x{result.ColumnCount}."; return CreateException(message, paramName); } internal static Exception DimensionsDontMatch(Matrix left, Matrix right, string paramName = null) where TException : Exception { var message = $"Matrix dimensions must agree: op1 is {left.RowCount}x{left.ColumnCount}, op2 is {right.RowCount}x{right.ColumnCount}."; return CreateException(message, paramName); } internal static Exception DimensionsDontMatch(Matrix matrix) where TException : Exception { var message = $"Matrix dimensions must agree: {matrix.RowCount}x{matrix.ColumnCount}."; return CreateException(message); } internal static Exception DimensionsDontMatch(Matrix left, Vector right, Vector result, string paramName = null) where TException : Exception { return DimensionsDontMatch(left, right.ToColumnMatrix(), result.ToColumnMatrix(), paramName); } internal static Exception DimensionsDontMatch(Matrix left, Vector right, string paramName = null) where TException : Exception { return DimensionsDontMatch(left, right.ToColumnMatrix(), paramName); } internal static Exception DimensionsDontMatch(Vector left, Matrix right, string paramName = null) where TException : Exception { return DimensionsDontMatch(left.ToColumnMatrix(), right, paramName); } internal static Exception DimensionsDontMatch(Vector left, Vector right, string paramName = null) where TException : Exception { return DimensionsDontMatch(left.ToColumnMatrix(), right.ToColumnMatrix(), paramName); } 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 } }