Math.NET Numerics
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1214 lines
51 KiB

// <copyright file="Matrix.Arithmetic.cs" company="Math.NET">
// 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-2013 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.
// </copyright>
using System;
using MathNet.Numerics.Properties;
namespace MathNet.Numerics.LinearAlgebra
{
/// <summary>
/// Defines the base class for <c>Matrix</c> classes.
/// </summary>
public abstract partial class Matrix<T>
{
/// <summary>
/// The value of 1.0.
/// </summary>
public static readonly T One = BuilderInstance<T>.Matrix.One;
/// <summary>
/// The value of 0.0.
/// </summary>
public static readonly T Zero = BuilderInstance<T>.Matrix.Zero;
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
protected abstract void DoNegate(Matrix<T> result);
/// <summary>
/// Complex conjugates each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the conjugation.</param>
protected abstract void DoConjugate(Matrix<T> result);
/// <summary>
/// Add a scalar to each element of the matrix and stores the result in the result vector.
/// </summary>
/// <param name="scalar">The scalar to add.</param>
/// <param name="result">The matrix to store the result of the addition.</param>
protected abstract void DoAdd(T scalar, Matrix<T> result);
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of the addition.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
protected abstract void DoAdd(Matrix<T> other, Matrix<T> result);
/// <summary>
/// Subtracts a scalar from each element of the matrix and stores the result in the result matrix.
/// </summary>
/// <param name="scalar">The scalar to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected abstract void DoSubtract(T scalar, Matrix<T> result);
/// <summary>
/// Subtracts each element of the matrix from a scalar and stores the result in the result matrix.
/// </summary>
/// <param name="scalar">The scalar to subtract from.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected void DoSubtractFrom(T scalar, Matrix<T> result)
{
DoNegate(result);
result.DoAdd(scalar, result);
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
protected abstract void DoSubtract(Matrix<T> other, Matrix<T> result);
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
protected abstract void DoMultiply(T scalar, Matrix<T> result);
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected abstract void DoMultiply(Vector<T> rightSide, Vector<T> result);
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected abstract void DoMultiply(Matrix<T> other, Matrix<T> result);
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected abstract void DoTransposeAndMultiply(Matrix<T> other, Matrix<T> result);
/// <summary>
/// Multiplies the transpose of this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected abstract void DoTransposeThisAndMultiply(Vector<T> rightSide, Vector<T> result);
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected abstract void DoTransposeThisAndMultiply(Matrix<T> other, Matrix<T> result);
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="divisor">The scalar denominator to use.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected abstract void DoDivide(T divisor, Matrix<T> result);
/// <summary>
/// Divides a scalar by each element of the matrix and stores the result in the result matrix.
/// </summary>
/// <param name="dividend">The scalar numerator to use.</param>
/// <param name="result">The matrix to store the result of the division.</param>
protected abstract void DoDivideByThis(T dividend, Matrix<T> result);
/// <summary>
/// Computes the modulus for the given divisor each element of the matrix.
/// </summary>
/// <param name="divisor">The scalar denominator to use.</param>
/// <param name="result">Matrix to store the results in.</param>
protected abstract void DoModulus(T divisor, Matrix<T> result);
/// <summary>
/// Computes the modulus for the given dividend for each element of the matrix.
/// </summary>
/// <param name="dividend">The scalar numerator to use.</param>
/// <param name="result">A vector to store the results in.</param>
protected abstract void DoModulusByThis(T dividend, Matrix<T> result);
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
protected abstract void DoPointwiseMultiply(Matrix<T> other, Matrix<T> result);
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="divisor">The pointwise denominator matrix to use.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
protected abstract void DoPointwiseDivide(Matrix<T> divisor, Matrix<T> result);
/// <summary>
/// Pointwise modulus this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="divisor">The pointwise denominator matrix to use</param>
/// <param name="result">The result of the modulus.</param>
protected abstract void DoPointwiseModulus(Matrix<T> divisor, Matrix<T> result);
/// <summary>
/// Adds a scalar to each element of the matrix.
/// </summary>
/// <param name="scalar">The scalar to add.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public Matrix<T> Add(T scalar)
{
if (scalar.Equals(Zero))
{
return Clone();
}
var result = CreateMatrix(RowCount, ColumnCount);
DoAdd(scalar, result);
return result;
}
/// <summary>
/// Adds a scalar to each element of the matrix and stores the result in the result matrix.
/// </summary>
/// <param name="scalar">The scalar to add.</param>
/// <param name="result">The matrix to store the result of the addition.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Add(T scalar, Matrix<T> result)
{
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, result, "result");
}
if (scalar.Equals(Zero))
{
CopyTo(result);
return;
}
DoAdd(scalar, result);
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <returns>The result of the addition.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public virtual Matrix<T> Add(Matrix<T> other)
{
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
var result = CreateMatrix(RowCount, ColumnCount);
DoAdd(other, result);
return result;
}
/// <summary>
/// Adds another matrix to this matrix.
/// </summary>
/// <param name="other">The matrix to add to this matrix.</param>
/// <param name="result">The matrix to store the result of the addition.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Add(Matrix<T> other, Matrix<T> result)
{
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other, "other");
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, result, "result");
}
DoAdd(other, result);
}
/// <summary>
/// Subtracts a scalar from each element of the matrix.
/// </summary>
/// <param name="scalar">The scalar to subtract.</param>
/// <returns>A new matrix containing the subtraction of this matrix and the scalar.</returns>
public Matrix<T> Subtract(T scalar)
{
if (scalar.Equals(Zero))
{
return Clone();
}
var result = CreateMatrix(RowCount, ColumnCount);
DoSubtract(scalar, result);
return result;
}
/// <summary>
/// Subtracts a scalar from each element of the matrix and stores the result in the result matrix.
/// </summary>
/// <param name="scalar">The scalar to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public void Subtract(T scalar, Matrix<T> result)
{
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, result, "result");
}
if (scalar.Equals(Zero))
{
CopyTo(result);
return;
}
DoSubtract(scalar, result);
}
/// <summary>
/// Subtracts each element of the matrix from a scalar.
/// </summary>
/// <param name="scalar">The scalar to subtract from.</param>
/// <returns>A new matrix containing the subtraction of the scalar and this matrix.</returns>
public Matrix<T> SubtractFrom(T scalar)
{
var result = CreateMatrix(RowCount, ColumnCount);
DoSubtractFrom(scalar, result);
return result;
}
/// <summary>
/// Subtracts each element of the matrix from a scalar and stores the result in the result matrix.
/// </summary>
/// <param name="scalar">The scalar to subtract from.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public void SubtractFrom(T scalar, Matrix<T> result)
{
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, result, "result");
}
DoSubtractFrom(scalar, result);
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <returns>The result of the subtraction.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public virtual Matrix<T> Subtract(Matrix<T> other)
{
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other);
}
var result = CreateMatrix(RowCount, ColumnCount);
DoSubtract(other, result);
return result;
}
/// <summary>
/// Subtracts another matrix from this matrix.
/// </summary>
/// <param name="other">The matrix to subtract.</param>
/// <param name="result">The matrix to store the result of the subtraction.</param>
/// <exception cref="ArgumentOutOfRangeException">If the two matrices don't have the same dimensions.</exception>
public void Subtract(Matrix<T> other, Matrix<T> result)
{
if (other.RowCount != RowCount || other.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, other, "other");
}
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(this, result, "result");
}
DoSubtract(other, result);
}
/// <summary>
/// Multiplies each element of this matrix with a scalar.
/// </summary>
/// <param name="scalar">The scalar to multiply with.</param>
/// <returns>The result of the multiplication.</returns>
public Matrix<T> 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;
}
/// <summary>
/// Multiplies each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to multiply the matrix with.</param>
/// <param name="result">The matrix to store the result of the multiplication.</param>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the same as this matrix.</exception>
public void Multiply(T scalar, Matrix<T> 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);
}
/// <summary>
/// Divides each element of this matrix with a scalar.
/// </summary>
/// <param name="scalar">The scalar to divide with.</param>
/// <returns>The result of the division.</returns>
public Matrix<T> 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;
}
/// <summary>
/// Divides each element of the matrix by a scalar and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide the matrix with.</param>
/// <param name="result">The matrix to store the result of the division.</param>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the same as this matrix.</exception>
public void Divide(T scalar, Matrix<T> 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);
}
/// <summary>
/// Divides a scalar by each element of the matrix.
/// </summary>
/// <param name="scalar">The scalar to divide.</param>
/// <returns>The result of the division.</returns>
public Matrix<T> DivideByThis(T scalar)
{
var result = CreateMatrix(RowCount, ColumnCount);
DoDivideByThis(scalar, result);
return result;
}
/// <summary>
/// Divides a scalar by each element of the matrix and places results into the result matrix.
/// </summary>
/// <param name="scalar">The scalar to divide.</param>
/// <param name="result">The matrix to store the result of the division.</param>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the same as this matrix.</exception>
public void DivideByThis(T scalar, Matrix<T> result)
{
if (result.RowCount != RowCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension, "result");
}
if (result.ColumnCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension, "result");
}
DoDivideByThis(scalar, result);
}
/// <summary>
/// Multiplies this matrix by a vector and returns the result.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentException">If <c>this.ColumnCount != rightSide.Count</c>.</exception>
public Vector<T> Multiply(Vector<T> rightSide)
{
if (ColumnCount != rightSide.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, rightSide, "rightSide");
}
var ret = CreateVector(RowCount);
DoMultiply(rightSide, ret);
return ret;
}
/// <summary>
/// Multiplies this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentException">If <strong>result.Count != this.RowCount</strong>.</exception>
/// <exception cref="ArgumentException">If <strong>this.ColumnCount != <paramref name="rightSide"/>.Count</strong>.</exception>
public virtual void Multiply(Vector<T> rightSide, Vector<T> result)
{
if (ColumnCount != rightSide.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, rightSide, "rightSide");
}
if (RowCount != result.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, result, "result");
}
if (ReferenceEquals(rightSide, result))
{
var tmp = result.CreateVector(result.Count);
DoMultiply(rightSide, tmp);
tmp.CopyTo(result);
}
else
{
DoMultiply(rightSide, result);
}
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ).
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentException">If <strong>this.RowCount != <paramref name="leftSide"/>.Count</strong>.</exception>
public Vector<T> LeftMultiply(Vector<T> leftSide)
{
if (RowCount != leftSide.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, leftSide, "leftSide");
}
var ret = CreateVector(ColumnCount);
DoLeftMultiply(leftSide, ret);
return ret;
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentException">If <strong>result.Count != this.ColumnCount</strong>.</exception>
/// <exception cref="ArgumentException">If <strong>this.RowCount != <paramref name="leftSide"/>.Count</strong>.</exception>
public virtual void LeftMultiply(Vector<T> leftSide, Vector<T> result)
{
if (RowCount != leftSide.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, leftSide, "leftSide");
}
if (ColumnCount != result.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, result, "result");
}
if (ReferenceEquals(leftSide, result))
{
var tmp = result.CreateVector(result.Count);
DoLeftMultiply(leftSide, tmp);
tmp.CopyTo(result);
}
else
{
DoLeftMultiply(leftSide, result);
}
}
/// <summary>
/// Left multiply a matrix with a vector ( = vector * matrix ) and place the result in the result vector.
/// </summary>
/// <param name="leftSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
protected void DoLeftMultiply(Vector<T> leftSide, Vector<T> result)
{
DoTransposeThisAndMultiply(leftSide, result);
}
/// <summary>
/// Multiplies this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the this.Rows x other.Columns.</exception>
public virtual void Multiply(Matrix<T> other, Matrix<T> result)
{
if (ColumnCount != other.RowCount || result.RowCount != RowCount || result.ColumnCount != other.ColumnCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, result);
}
if (ReferenceEquals(this, result) || ReferenceEquals(other, result))
{
var tmp = result.CreateMatrix(result.RowCount, result.ColumnCount);
DoMultiply(other, tmp);
tmp.CopyTo(result);
}
else
{
DoMultiply(other, result);
}
}
/// <summary>
/// Multiplies this matrix with another matrix and returns the result.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
/// <returns>The result of the multiplication.</returns>
public virtual Matrix<T> Multiply(Matrix<T> other)
{
if (ColumnCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
var result = CreateMatrix(RowCount, other.ColumnCount);
DoMultiply(other, result);
return result;
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.ColumnCount</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the this.RowCount x other.RowCount.</exception>
public virtual void TransposeAndMultiply(Matrix<T> other, Matrix<T> result)
{
if (ColumnCount != other.ColumnCount || result.RowCount != RowCount || result.ColumnCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, result);
}
if (ReferenceEquals(this, result) || ReferenceEquals(other, result))
{
var tmp = result.CreateMatrix(result.RowCount, result.ColumnCount);
DoTransposeAndMultiply(other, tmp);
tmp.CopyTo(result);
}
else
{
DoTransposeAndMultiply(other, result);
}
}
/// <summary>
/// Multiplies this matrix with transpose of another matrix and returns the result.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Columns != other.ColumnCount</strong>.</exception>
/// <returns>The result of the multiplication.</returns>
public virtual Matrix<T> TransposeAndMultiply(Matrix<T> other)
{
if (ColumnCount != other.ColumnCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
var result = CreateMatrix(RowCount, other.RowCount);
DoTransposeAndMultiply(other, result);
return result;
}
/// <summary>
/// Multiplies the transpose of this matrix by a vector and returns the result.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <returns>The result of the multiplication.</returns>
/// <exception cref="ArgumentException">If <c>this.RowCount != rightSide.Count</c>.</exception>
public Vector<T> TransposeThisAndMultiply(Vector<T> rightSide)
{
if (RowCount != rightSide.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, rightSide, "rightSide");
}
var ret = CreateVector(ColumnCount);
DoTransposeThisAndMultiply(rightSide, ret);
return ret;
}
/// <summary>
/// Multiplies the transpose of this matrix with a vector and places the results into the result vector.
/// </summary>
/// <param name="rightSide">The vector to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentException">If <strong>result.Count != this.ColumnCount</strong>.</exception>
/// <exception cref="ArgumentException">If <strong>this.RowCount != <paramref name="rightSide"/>.Count</strong>.</exception>
public void TransposeThisAndMultiply(Vector<T> rightSide, Vector<T> result)
{
if (RowCount != rightSide.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, rightSide, "rightSide");
}
if (ColumnCount != result.Count)
{
throw DimensionsDontMatch<ArgumentException>(this, result, "result");
}
if (ReferenceEquals(rightSide, result))
{
var tmp = result.CreateVector(result.Count);
DoTransposeThisAndMultiply(rightSide, tmp);
tmp.CopyTo(result);
}
else
{
DoTransposeThisAndMultiply(rightSide, result);
}
}
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and places the results into the result matrix.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <param name="result">The result of the multiplication.</param>
/// <exception cref="ArgumentException">If <strong>this.Rows != other.RowCount</strong>.</exception>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not the this.ColumnCount x other.ColumnCount.</exception>
public void TransposeThisAndMultiply(Matrix<T> other, Matrix<T> result)
{
if (RowCount != other.RowCount || result.RowCount != ColumnCount || result.ColumnCount != other.ColumnCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, result);
}
if (ReferenceEquals(this, result) || ReferenceEquals(other, result))
{
var tmp = result.CreateMatrix(result.RowCount, result.ColumnCount);
DoTransposeThisAndMultiply(other, tmp);
tmp.CopyTo(result);
}
else
{
DoTransposeThisAndMultiply(other, result);
}
}
/// <summary>
/// Multiplies the transpose of this matrix with another matrix and returns the result.
/// </summary>
/// <param name="other">The matrix to multiply with.</param>
/// <exception cref="ArgumentException">If <strong>this.Rows != other.RowCount</strong>.</exception>
/// <returns>The result of the multiplication.</returns>
public Matrix<T> TransposeThisAndMultiply(Matrix<T> other)
{
if (RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other);
}
var result = CreateMatrix(ColumnCount, other.ColumnCount);
DoTransposeThisAndMultiply(other, result);
return result;
}
/// <summary>
/// Negate each element of this matrix.
/// </summary>
/// <returns>A matrix containing the negated values.</returns>
public Matrix<T> Negate()
{
var result = CreateMatrix(RowCount, ColumnCount);
DoNegate(result);
return result;
}
/// <summary>
/// Negate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the negation.</param>
/// <exception cref="ArgumentException">if the result matrix's dimensions are not the same as this matrix.</exception>
public void Negate(Matrix<T> result)
{
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentException>(this, result);
}
DoNegate(result);
}
/// <summary>
/// Complex conjugate each element of this matrix.
/// </summary>
/// <returns>A matrix containing the conjugated values.</returns>
public Matrix<T> Conjugate()
{
var result = CreateMatrix(RowCount, ColumnCount);
DoConjugate(result);
return result;
}
/// <summary>
/// Complex conjugate each element of this matrix and place the results into the result matrix.
/// </summary>
/// <param name="result">The result of the conjugation.</param>
/// <exception cref="ArgumentException">if the result matrix's dimensions are not the same as this matrix.</exception>
public void Conjugate(Matrix<T> result)
{
if (result.RowCount != RowCount || result.ColumnCount != ColumnCount)
{
throw DimensionsDontMatch<ArgumentException>(this, result);
}
DoConjugate(result);
}
/// <summary>
/// Computes the modulus (matrix % divisor) for each element of the matrix.
/// </summary>
/// <param name="divisor">The scalar denominator to use.</param>
/// <returns>A matrix containing the results.</returns>
public Matrix<T> Modulus(T divisor)
{
var result = CreateMatrix(RowCount, ColumnCount);
DoModulus(divisor, result);
return result;
}
/// <summary>
/// Computes the modulus (matrix % divisor) for each element of the matrix.
/// </summary>
/// <param name="divisor">The scalar denominator to use.</param>
/// <param name="result">Matrix to store the results in.</param>
public void Modulus(T divisor, Matrix<T> result)
{
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, result);
}
DoModulus(divisor, result);
}
/// <summary>
/// Computes the modulus (dividend % matrix) for each element of the matrix.
/// </summary>
/// <param name="dividend">The scalar numerator to use.</param>
/// <returns>A matrix containing the results.</returns>
public Matrix<T> ModulusByThis(T dividend)
{
var result = CreateMatrix(RowCount, ColumnCount);
DoModulusByThis(dividend, result);
return result;
}
/// <summary>
/// Computes the modulus (dividend % matrix) for each element of the matrix.
/// </summary>
/// <param name="dividend">The scalar numerator to use.</param>
/// <param name="result">Matrix to store the results in.</param>
public void ModulusByThis(T dividend, Matrix<T> result)
{
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, result);
}
DoModulusByThis(dividend, result);
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise multiplication of this matrix and <paramref name="other"/>.</returns>
public Matrix<T> PointwiseMultiply(Matrix<T> other)
{
if (ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, "other");
}
var result = CreateMatrix(RowCount, ColumnCount);
DoPointwiseMultiply(other, result);
return result;
}
/// <summary>
/// Pointwise multiplies this matrix with another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="other">The matrix to pointwise multiply with this one.</param>
/// <param name="result">The matrix to store the result of the pointwise multiplication.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="other"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public void PointwiseMultiply(Matrix<T> other, Matrix<T> result)
{
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != other.ColumnCount || RowCount != other.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, other, result);
}
DoPointwiseMultiply(other, result);
}
/// <summary>
/// Pointwise divide this matrix by another matrix.
/// </summary>
/// <param name="divisor">The pointwise denominator matrix to use.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="divisor"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise division of this matrix and <paramref name="divisor"/>.</returns>
public Matrix<T> PointwiseDivide(Matrix<T> divisor)
{
if (ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, divisor);
}
var result = CreateMatrix(RowCount, ColumnCount);
DoPointwiseDivide(divisor, result);
return result;
}
/// <summary>
/// Pointwise divide this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="divisor">The pointwise denominator matrix to use.</param>
/// <param name="result">The matrix to store the result of the pointwise division.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="divisor"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public void PointwiseDivide(Matrix<T> divisor, Matrix<T> result)
{
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, divisor, result);
}
DoPointwiseDivide(divisor, result);
}
/// <summary>
/// Pointwise modulus this matrix by another matrix.
/// </summary>
/// <param name="divisor">The pointwise denominator matrix to use.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="divisor"/> are not the same size.</exception>
/// <returns>A new matrix that is the pointwise modulus of this matrix and <paramref name="divisor"/>.</returns>
public Matrix<T> PointwiseModulus(Matrix<T> divisor)
{
if (ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, divisor);
}
var result = CreateMatrix(RowCount, ColumnCount);
DoPointwiseModulus(divisor, result);
return result;
}
/// <summary>
/// Pointwise modulus this matrix by another matrix and stores the result into the result matrix.
/// </summary>
/// <param name="divisor">The pointwise denominator matrix to use.</param>
/// <param name="result">The matrix to store the result of the pointwise modulus.</param>
/// <exception cref="ArgumentException">If this matrix and <paramref name="divisor"/> are not the same size.</exception>
/// <exception cref="ArgumentException">If this matrix and <paramref name="result"/> are not the same size.</exception>
public void PointwiseModulus(Matrix<T> divisor, Matrix<T> result)
{
if (ColumnCount != result.ColumnCount || RowCount != result.RowCount || ColumnCount != divisor.ColumnCount || RowCount != divisor.RowCount)
{
throw DimensionsDontMatch<ArgumentException>(this, divisor, result);
}
DoPointwiseModulus(divisor, result);
}
/// <summary>
/// Computes the trace of this matrix.
/// </summary>
/// <returns>The trace of this matrix</returns>
/// <exception cref="ArgumentException">If the matrix is not square</exception>
public abstract T Trace();
/// <summary>
/// Calculates the rank of the matrix
/// </summary>
/// <returns>effective numerical rank, obtained from SVD</returns>
public virtual int Rank()
{
return Svd(false).Rank;
}
/// <summary>Calculates the condition number of this matrix.</summary>
/// <returns>The condition number of the matrix.</returns>
/// <remarks>The condition number is calculated using singular value decomposition.</remarks>
public virtual T ConditionNumber()
{
return Svd(false).ConditionNumber;
}
/// <summary>Computes the determinant of this matrix.</summary>
/// <returns>The determinant of this matrix.</returns>
public virtual T Determinant()
{
if (RowCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
return LU().Determinant;
}
/// <summary>Computes the inverse of this matrix.</summary>
/// <returns>The inverse of this matrix.</returns>
public virtual Matrix<T> Inverse()
{
if (RowCount != ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare);
}
return LU().Inverse();
}
/// <summary>
/// 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.
/// </summary>
/// <param name="other">The other matrix.</param>
/// <returns>The kronecker product of the two matrices.</returns>
public Matrix<T> KroneckerProduct(Matrix<T> other)
{
var result = CreateMatrix(RowCount*other.RowCount, ColumnCount*other.ColumnCount);
KroneckerProduct(other, result);
return result;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="other">The other matrix.</param>
/// <param name="result">The kronecker product of the two matrices.</param>
/// <exception cref="ArgumentException">If the result matrix's dimensions are not (this.Rows * lower.rows) x (this.Columns * lower.Columns).</exception>
public virtual void KroneckerProduct(Matrix<T> other, Matrix<T> result)
{
if (result.RowCount != (RowCount*other.RowCount) || result.ColumnCount != (ColumnCount*other.ColumnCount))
{
throw DimensionsDontMatch<ArgumentOutOfRangeException>(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);
}
}
}
/// <summary>
/// Normalizes the columns of a matrix.
/// </summary>
/// <param name="p">The norm under which to normalize the columns under.</param>
/// <returns>A normalized version of the matrix.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the parameter p is not positive.</exception>
public Matrix<T> NormalizeColumns(int p)
{
if (p < 1)
{
throw new ArgumentOutOfRangeException("p", Resources.ArgumentMustBePositive);
}
var ret = CreateMatrix(RowCount, ColumnCount);
for (var index = 0; index < ColumnCount; index++)
{
ret.SetColumn(index, Column(index).Normalize(p));
}
return ret;
}
/// <summary>
/// Normalizes the rows of a matrix.
/// </summary>
/// <param name="p">The norm under which to normalize the rows under.</param>
/// <returns>A normalized version of the matrix.</returns>
/// <exception cref="ArgumentOutOfRangeException">If the parameter p is not positive.</exception>
public Matrix<T> NormalizeRows(int p)
{
if (p < 1)
{
throw new ArgumentOutOfRangeException("p", Resources.ArgumentMustBePositive);
}
var ret = CreateMatrix(RowCount, ColumnCount);
for (var index = 0; index < RowCount; index++)
{
ret.SetRow(index, Row(index).Normalize(p));
}
return ret;
}
#region Exceptions - possibly move elsewhere?
internal static Exception DimensionsDontMatch<TException>(Matrix<T> left, Matrix<T> right, Matrix<T> 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<TException>(message, paramName);
}
internal static Exception DimensionsDontMatch<TException>(Matrix<T> left, Matrix<T> 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<TException>(message, paramName);
}
internal static Exception DimensionsDontMatch<TException>(Matrix<T> matrix)
where TException : Exception
{
var message = string.Format(Resources.ArgumentMatrixDimensions1, matrix.RowCount + "x" + matrix.ColumnCount);
return CreateException<TException>(message);
}
internal static Exception DimensionsDontMatch<TException>(Matrix<T> left, Vector<T> right, Vector<T> result, string paramName = null)
where TException : Exception
{
return DimensionsDontMatch<TException>(left, right.ToColumnMatrix(), result.ToColumnMatrix(), paramName);
}
internal static Exception DimensionsDontMatch<TException>(Matrix<T> left, Vector<T> right, string paramName = null)
where TException : Exception
{
return DimensionsDontMatch<TException>(left, right.ToColumnMatrix(), paramName);
}
internal static Exception DimensionsDontMatch<TException>(Vector<T> left, Matrix<T> right, string paramName = null)
where TException : Exception
{
return DimensionsDontMatch<TException>(left.ToColumnMatrix(), right, paramName);
}
internal static Exception DimensionsDontMatch<TException>(Vector<T> left, Vector<T> right, string paramName = null)
where TException : Exception
{
return DimensionsDontMatch<TException>(left.ToColumnMatrix(), right.ToColumnMatrix(), paramName);
}
static Exception CreateException<TException>(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
}
}