using System;
using System.Collections.Generic;
using System.Text;
using DataStructuresDotNet.Misc;
namespace DataStructuresDotNet.DataStructures
{
/// <summary>
/// A Matrix datastructure corresponding to the mathematical matrix used in linear algebra.
/// </summary>
public class Matrix : IVisitableCollection<double>
{
#region Globals
private int noOfRows;
private int noOfColumns;
private double[,] data;
#endregion
#region Construction
/// <summary>
/// Initializes a new instance of the <see cref="Matrix"/> class.
/// </summary>
/// <param name="rows_">The number of rows in the matrix.</param>
/// <param name="columns_">The number of columns in the matrix.</param>
public Matrix(int rows_, int columns_)
{
if ((rows_ <= 0) || (columns_ <= 0))
{
throw new ArgumentException(Resources.RowsOrColumnsInvalid);
}
this.noOfRows = rows_;
this.noOfColumns = columns_;
data = new double[noOfRows, noOfColumns];
}
#endregion
#region Public Members
/// <summary>
/// Gets the number of rows in this matrix.
/// </summary>
/// <value>The rows.</value>
public int Rows
{
get
{
return noOfRows;
}
}
/// <summary>
/// Gets the number of columns in this matrix.
/// </summary>
/// <value>The columns.</value>
public int Columns
{
get
{
return noOfColumns;
}
}
/// <summary>
/// Times the matrices according to the linear algebra operator *.
/// </summary>
/// <param name="matrix">The result of the times operation.</param>
/// <returns></returns>
public Matrix Times(Matrix matrix)
{
// Check the dimensions to make sure the operation is a valid one.
if (noOfColumns != matrix.noOfRows)
{
throw new ArgumentException(Resources.IncompatibleMatricesTimes);
}
Matrix ret = new Matrix(noOfRows, matrix.noOfColumns);
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < matrix.noOfColumns; j++)
{
double sum = 0;
for (int k = 0; k < noOfColumns; k++)
{
sum += (data[i, k] * matrix.data[k, j]);
}
ret.data[i, j] = sum;
}
}
return ret;
}
/// <summary>
/// Times the matrices according to the linear algebra operator *.
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public Matrix Times(double number)
{
Matrix ret = new Matrix(noOfRows, noOfColumns);
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
ret[i, j] = this[i, j] * number;
}
}
return ret;
}
/// <summary>
/// Adds to matrices according to the linear algebra operator +.
/// </summary>
/// <param name="matrix">The result of the addition.</param>
/// <returns></returns>
public Matrix Plus(Matrix matrix)
{
if ((this.noOfRows != matrix.noOfRows) || (this.noOfColumns != matrix.noOfColumns))
{
throw new ArgumentException(Resources.IncompatibleMatricesSameSize);
}
Matrix ret = new Matrix(noOfRows, noOfColumns);
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
ret[i, j] = this[i, j] + matrix[i, j];
}
}
return ret;
}
/// <summary>
/// Inverts this instance.
/// </summary>
/// <returns></returns>
public Matrix Invert()
{
return this * -1;
}
/// <summary>
/// Subtracts the matrices according to the linear algebra operator -.
/// </summary>
/// <param name="matrix">The result of the subtraction.</param>
/// <returns></returns>
public Matrix Minus(Matrix matrix)
{
if (matrix == null)
{
throw new ArgumentNullException(Resources.MatrixIsNull);
}
return this + matrix.Invert();
}
/// <summary>
/// Transposes the matrix.
/// </summary>
/// <returns></returns>
/// <value>The transposed matrix.</value>
public Matrix Transpose()
{
Matrix ret = new Matrix(noOfColumns, noOfRows);
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
ret[j, i] = this[i, j];
}
}
return ret;
}
#endregion
#region Operator Overloads
/// <summary>
/// Gets or sets the value at the specified index.
/// </summary>
/// <value></value>
public double this[int i, int j]
{
get
{
return data[i, j];
}
set
{
data[i, j] = value;
}
}
/// <summary>
/// Overload of the operator + as in linear algebra.
/// </summary>
/// <param name="m1">The left hand matrix.</param>
/// <param name="m2">The right hand matrix.</param>
/// <returns></returns>
public static Matrix operator +(Matrix m1, Matrix m2)
{
return m1.Plus(m2);
}
/*
/// <summary>
/// Operator overload for the IsEqual method.
/// </summary>
/// <param name="m1">The left hand matrix.</param>
/// <param name="m2">The right hand matrix</param>
/// <returns></returns>
public static Matrix operator ==(Matrix m1, Matrix m2)
{
return m1.IsEqual(m2);
}
/// <summary>
/// Operator overload for the IsEqual method.
/// </summary>
/// <param name="m1">The left hand matrix.</param>
/// <param name="m2">The right hand matrix</param>
/// <returns></returns>
public static Matrix operator !=(Matrix m1, Matrix m2)
{
return !m1.IsEqual(m2);
}
*/
/// <summary>
/// Overload of the operator - as in linear algebra.
/// </summary>
/// <param name="m1">The left hand matrix.</param>
/// <param name="m2">The right hand matrix.</param>
/// <returns></returns>
public static Matrix operator -(Matrix m1, Matrix m2)
{
return m1.Minus(m2);
}
/// <summary>
/// Overload of the operator * as in linear algebra.
/// </summary>
/// <param name="m1">The left hand matrix.</param>
/// <param name="m2">The right hand matrix.</param>
/// <returns></returns>
public static Matrix operator *(Matrix m1, Matrix m2)
{
return m1.Times(m2);
}
/// <summary>
/// Overload of the operator * as in linear algebra.
/// </summary>
/// <param name="number">The number.</param>
/// <param name="m2">The right hand matrix.</param>
/// <returns></returns>
public static Matrix operator *(double number, Matrix m2)
{
return m2.Times(number);
}
/// <summary>
/// Overload of the operator * as in linear algebra.
/// </summary>
/// <param name="m1">The number to be multiplied with.</param>
/// <param name="number">The number.</param>
/// <returns></returns>
public static Matrix operator *(Matrix m1, double number)
{
return m1.Times(number);
}
/// <summary>
/// Determines whether the specified matrix is equal to the current one (length, width, values).
/// </summary>
/// <param name="m">The matrix to be compared to.</param>
/// <returns>
/// <c>true</c> if the specified matrix is equal to the current one; otherwise, <c>false</c>.
/// </returns>
public bool IsEqual(Matrix m)
{
if (m == null)
{
return false;
}
if (m.Rows != Rows)
{
return false;
}
if (m.Columns != Columns)
{
return false;
}
for (int i = 0; i < Rows; i++)
{
for (int j = 0; j < Columns; j++)
{
if (this[i, j] != m[i, j])
{
return false;
}
}
}
return true;
}
/// <summary>
/// Gets a value indicating whether this matrix instance is symmetric.
/// </summary>
/// <value>
/// <c>true</c> if this matrix instance is symmetric; otherwise, <c>false</c>.
/// </value>
public bool IsSymmetric
{
get
{
if (Rows == Columns)
{
return this.IsEqual(this.Transpose());
}
else
{
return false;
}
}
}
#endregion
#region IVisitableCollection<double> Members
/// <summary>
/// Gets a value indicating whether this instance is of a fixed size.
/// </summary>
/// <value>
/// <c>true</c> if this instance is fixed size; otherwise, <c>false</c>.
/// </value>
public bool IsFixedSize
{
get {
return true;
}
}
/// <summary>
/// Gets a value indicating whether this collection is empty.
/// </summary>
/// <value>
/// <c>true</c> if this collection is empty; otherwise, <c>false</c>.
/// </value>
public bool IsEmpty
{
get {
return false;
}
}
/// <summary>
/// Gets a value indicating whether this collection is full.
/// </summary>
/// <value><c>true</c> if this collection is full; otherwise, <c>false</c>.</value>
public bool IsFull
{
get {
return false;
}
}
/// <summary>
/// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"></see>.
/// </summary>
/// <value></value>
/// <returns>The number of elements contained in the <see cref="T:System.Collections.ICollection"></see>.</returns>
public int Count
{
get
{
return noOfRows * noOfColumns;
}
}
/// <summary>
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"></see> contains a specific value.
/// </summary>
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
/// <returns>
/// true if item is found in the <see cref="T:System.Collections.Generic.ICollection`1"></see>; otherwise, false.
/// </returns>
public bool Contains(double item)
{
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
if (this[i, j] == item)
{
return true;
}
}
}
return false;
}
/// <summary>
/// Accepts the specified visitor.
/// </summary>
/// <param name="visitor">The visitor.</param>
public void Accept(DataStructuresDotNet.Visitors.IVisitor<double> visitor)
{
if (visitor == null)
{
throw new ArgumentNullException("visitor");
}
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
visitor.Visit(this[i, j]);
}
}
}
/// <summary>
/// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"></see> to an <see cref="T:System.Array"></see>, starting at a particular <see cref="T:System.Array"></see> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="T:System.Array"></see> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"></see>. The <see cref="T:System.Array"></see> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
/// <exception cref="T:System.ArgumentOutOfRangeException">arrayIndex is less than 0.</exception>
/// <exception cref="T:System.ArgumentNullException">array is null.</exception>
/// <exception cref="T:System.ArgumentException">array is multidimensional.-or-arrayIndex is equal to or greater than the length of array.-or-The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"></see> is greater than the available space from arrayIndex to the end of the destination array.-or-Type T cannot be cast automatically to the type of the destination array.</exception>
public void CopyTo(double[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if ((array.Length - arrayIndex) < this.Count)
{
throw new ArgumentException(Resources.NotEnoughSpaceInTargetArray);
}
int counter = arrayIndex;
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
array.SetValue(this[i, j], counter);
counter++;
}
}
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> that can be used to iterate through the collection.
/// </returns>
public IEnumerator<double> GetEnumerator()
{
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
yield return data[i, j];
}
}
}
/// <summary>
/// Clears all the objects in this instance.
/// </summary>
public void Clear()
{
for (int i = 0; i < noOfRows; i++)
{
for (int j = 0; j < noOfColumns; j++)
{
data[i, j] = 0;
}
}
}
/// <summary>
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"></see>.
/// </summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"></see> is read-only.</exception>
void ICollection<double>.Add(double item)
{
throw new NotSupportedException();
}
/// <summary>
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"></see>.
/// </summary>
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
/// <returns>
/// true if item was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"></see>; otherwise, false. This method also returns false if item is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"></see>.
/// </returns>
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"></see> is read-only.</exception>
bool ICollection<double>.Remove(double item)
{
throw new NotSupportedException();
}
/// <summary>
/// Compares the current instance with another object of the same type.
/// </summary>
/// <param name="obj">An object to compare with this instance.</param>
/// <returns>
/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than obj. Zero This instance is equal to obj. Greater than zero This instance is greater than obj.
/// </returns>
/// <exception cref="T:System.ArgumentException">obj is not the same type as this instance. </exception>
public int CompareTo(object obj)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
if (obj.GetType() == this.GetType())
{
Matrix m = obj as Matrix;
return this.Count.CompareTo(m.Count);
}
else
{
return this.GetType().FullName.CompareTo(obj.GetType().FullName);
}
}
#endregion
#region ICollection<double> Members
/// <summary>
/// Gets a value indicating whether this instance is read only.
/// </summary>
/// <value>
/// <c>true</c> if this instance is read only; otherwise, <c>false</c>.
/// </value>
public bool IsReadOnly
{
get {
return false;
}
}
#endregion
#region IEnumerable Members
/// <summary>
/// Gets the enumerator.
/// </summary>
/// <returns></returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
}
}