using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
#if ALGLIB
using alglib;
#endif
namespace miew.Matrix
{
using Math = System.Math;
using String = System.String;
[DebuggerDisplay("{_DebugString()}")]
public class Matrix
{
private double[,] _values;
private int c_rows;
private int c_cols;
private String _DebugString() { return String.Format("{0} rows by {1} columns", c_rows, c_cols); }
public Matrix(int rowCount, int columnCount)
{
c_rows = rowCount;
c_cols = columnCount;
_values = new double[c_rows, c_cols];
}
public Matrix(double[] v)
: this(v.Length, v.Length)
{
for (int i = 0; i < v.Length; i++)
_values[i, i] = v[i];
}
public Matrix(double[] v, int c_take)
: this(c_take, c_take)
{
c_take = Math.Min(c_take, v.Length);
for (int i = 0; i < c_take; i++)
_values[i, i] = v[i];
}
public Matrix(double[,] m)
: this(m.GetLength(0), m.GetLength(1))
{
for (int i = 0; i < c_rows; i++)
for (int j = 0; j < c_cols; j++)
_values[i, j] = m[i, j];
}
public double this[int row, int column]
{
get { return _values[row, column]; }
set { _values[row, column] = value; }
}
public int RowCount { get { return c_rows; } }
public int ColumnCount { get { return c_cols; } }
public double[] Row(int i)
{
double[] v = new double[ColumnCount];
for (int j = 0; j < ColumnCount; j++)
v[j] = _values[i, j];
return v;
}
public double[] Column(int j)
{
double[] v = new double[RowCount];
for (int i = 0; i < RowCount; i++)
v[i] = _values[i, j];
return v;
}
public IEnumerable<double[]> Rows
{
get
{
//int x = _values.Cast<Double>().Count(); // can access all in [,] this way
for (int i = 0; i < RowCount; i++)
yield return Row(i);
}
}
public IEnumerable<double[]> Columns
{
get
{
for (int i = 0; i < ColumnCount; i++)
yield return Column(i);
}
}
public void CleaveVertical(int left_cols, out Matrix left, out Matrix right)
{
if (left_cols == ColumnCount)
{
left = new Matrix(this);
right = new Matrix(RowCount, 0);
}
else if (left_cols == 0)
{
left = new Matrix(RowCount, 0);
right = new Matrix(this);
}
else if (left_cols > ColumnCount)
throw new Exception();
else
{
left = new double[RowCount, left_cols];
right = new double[RowCount, ColumnCount - left_cols];
for (int i = 0; i < RowCount; i++)
for (int j = 0; j < ColumnCount; j++)
if (j < left_cols)
left[i, j] = _values[i, j];
else
right[i, j - left_cols] = _values[i, j];
}
}
public void CleaveHorizontal(int top_rows, out Matrix top, out Matrix bottom)
{
if (top_rows == RowCount)
{
top = new Matrix(this);
bottom = new Matrix(0, ColumnCount);
}
else if (top_rows == 0)
{
top = new Matrix(0, ColumnCount);
bottom = new Matrix(this);
}
else if (top_rows > RowCount)
throw new Exception();
else
{
top = new double[top_rows, ColumnCount];
bottom = new double[RowCount - top_rows, ColumnCount];
for (int i = 0; i < RowCount; i++)
for (int j = 0; j < ColumnCount; j++)
if (i < top_rows)
top[i, j] = _values[i, j];
else
bottom[i - top_rows, j] = _values[i, j];
}
}
public void SetColumnValues(int j, double[] v)
{
if (v.Length != RowCount)
throw new Exception();
for (int i = 0; i < RowCount; i++)
_values[i, j] = v[i];
}
public static Matrix Identity(int size)
{
Matrix m = new Matrix(size, size);
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
m[i, j] = (i == j) ? 1.0 : 0.0;
return m;
}
public Matrix Transpose()
{
Matrix m = new Matrix(c_cols, c_rows);
for (int i = 0; i < c_rows; i++)
for (int j = 0; j < c_cols; j++)
m[j, i] = this[i, j];
return m;
}
public static Matrix Add(Matrix m_l, Matrix m_r)
{
Debug.Assert(m_l.ColumnCount == m_r.ColumnCount);
Debug.Assert(m_l.RowCount == m_r.RowCount);
Matrix m = new Matrix(m_l.RowCount, m_r.ColumnCount);
for (int i = 0; i < m_l.RowCount; i++)
for (int j = 0; j < m_l.ColumnCount; j++)
m[i, j] = m_l[i, j] + m_r[i, j];
return m;
}
public static Matrix Subtract(Matrix m_l, Matrix m_r)
{
Debug.Assert(m_l.ColumnCount == m_r.ColumnCount);
Debug.Assert(m_l.RowCount == m_r.RowCount);
Matrix m = new Matrix(m_l.RowCount, m_r.ColumnCount);
for (int i = 0; i < m_l.RowCount; i++)
for (int j = 0; j < m_l.ColumnCount; j++)
m[i, j] = m_l[i, j] - m_r[i, j];
return m;
}
public static Matrix Multiply(Matrix m_l, Matrix m_r)
{
if (m_l.ColumnCount != m_r.RowCount)
throw new Exception();
Matrix m = new Matrix(m_l.RowCount, m_r.ColumnCount);
for (int i = 0; i < m.ColumnCount; i++)
{
for (int j = 0; j < m_l.RowCount; j++)
{
double value = 0.0;
for (int k = 0; k < m_r.RowCount; k++)
value += m_l[j, k] * m_r[k, i];
m[j, i] = value;
}
}
return m;
}
public static Matrix Multiply(double left, Matrix m_r)
{
Matrix m = new Matrix(m_r.RowCount, m_r.ColumnCount);
for (int i = 0; i < m.RowCount; i++)
for (int j = 0; j < m_r.ColumnCount; j++)
m[i, j] = left * m_r[i, j];
return m;
}
public static Matrix Multiply(Matrix m_l, double right)
{
Matrix m = new Matrix(m_l.RowCount, m_l.ColumnCount);
for (int i = 0; i < m_l.RowCount; i++)
for (int j = 0; j < m_l.ColumnCount; j++)
m[i, j] = m_l[i, j] * right;
return m;
}
public static Matrix Divide(Matrix m_l, double right)
{
Matrix m = new Matrix(m_l.RowCount, m_l.ColumnCount);
for (int i = 0; i < m_l.RowCount; i++)
for (int j = 0; j < m_l.ColumnCount; j++)
m[i, j] = m_l[i, j] / right;
return m;
}
public static double[] DiagonalVector(Matrix m)
{
Debug.Assert(m.RowCount == m.ColumnCount);
double[] v = new double[m.RowCount];
for (int i = 0; i < m.RowCount; i++)
v[i] = m[i, i];
return v;
}
public static double[,] ToDoubleArray(Matrix m)
{
double[,] result = new double[m.RowCount, m.ColumnCount];
for (int i = 0; i < m.RowCount; i++)
for (int j = 0; j < m.ColumnCount; j++)
result[i, j] = m[i, j];
return result;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < RowCount; i++)
{
for (int j = 0; j < ColumnCount; j++)
sb.Append(_values[i, j].ToString("N4").PadLeft(8) + " ");
sb.AppendLine();
}
return sb.ToString();
}
public Matrix Trim(int r0, int c0)
{
if (RowCount <= r0 && ColumnCount <= c0)
return new Matrix(this);
double[,] _new = new double[r0, c0];
for (int i = 0; i < r0; i++)
for (int j = 0; j < c0; j++)
_new[i, j] = _values[i, j];
return new Matrix(_new);
}
public Matrix TakeKRows(int k) { return Trim(k, ColumnCount); }
public Matrix TakeKColumns(int k) { return Trim(RowCount, k); }
public Matrix TakeKRowsAndColumns(int k) { return Trim(k, k); }
public void NormalizeColumns()
{
double[] lengths = new double[ColumnCount];
for (int i = 0; i < RowCount; i++)
for (int j = 0; j < ColumnCount; j++)
lengths[j] += Math.Pow(_values[i, j], 2);
for (int j = 0; j < ColumnCount; j++)
lengths[j] = Math.Sqrt(lengths[j]);
for (int i = 0; i < RowCount; i++)
for (int j = 0; j < ColumnCount; j++)
_values[i, j] /= lengths[j];
}
public static Matrix operator +(Matrix m_l, Matrix m_r) { return Matrix.Add(m_l, m_r); }
public static Matrix operator -(Matrix m_l, Matrix m_r) { return Matrix.Subtract(m_l, m_r); }
public static Matrix operator *(Matrix m_l, Matrix m_r) { return Matrix.Multiply(m_l, m_r); }
public static Matrix operator *(double left, Matrix m_r) { return Matrix.Multiply(left, m_r); }
public static Matrix operator *(Matrix m_l, double right) { return Matrix.Multiply(m_l, right); }
public static Matrix operator /(Matrix m_l, double right) { return Matrix.Divide(m_l, right); }
public static implicit operator Matrix(double[,] m) { return new Matrix(m); }
public static implicit operator double[,](Matrix m) { return ToDoubleArray(m); }
#if ALGLIB
/// <summary>
/// Make alglib's SVD nicer by using the above type
/// </summary>
public static bool SingularValueDecomposition(Matrix A, out double[] w, out Matrix V)
{
w = null;
V = null;
double[,] u = null;
double[,] v = null;
if (!svd.rmatrixsvd(A, A.RowCount, A.ColumnCount, 0, 1, 2, ref w, ref u, ref v))
return false;
V = new Matrix(v);
return true;
}
#endif
};
}