BotSharp/BotSharp.Algorithm/HiddenMarkovModel/MathUtils/LinearAlgebra/MatrixOp.cs
2018-09-17 07:31:54 -05:00

422 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace BotSharp.Algorithm.HiddenMarkovModel.MathUtils.LinearAlgebra
{
public class MatrixOp
{
public static double[] ElementWiseAbs(double[] x)
{
int n = x.Length;
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = System.Math.Abs(x[i]);
}
return result;
}
public static double[][] DiagonalMatrix(double[] x)
{
int n = x.Length;
double[][] matrix = new double[n][];
for (int i = 0; i < n; ++i)
{
matrix[i] = new double[n];
matrix[i][i] = x[i];
}
return matrix;
}
public static double[][] Transpose(double[][] x)
{
int rowCount = x.Length;
int colCount = x[0].Length;
double[][] xt = new double[colCount][];
for (int i = 0; i < colCount; ++i)
{
xt[i] = new double[rowCount];
for (int j = 0; j < rowCount; ++j)
{
xt[i][j] = x[j][i];
}
}
return xt;
}
public static double[] ElementWiseMinus(double[] x, double[] y)
{
int n = x.Length;
Debug.Assert(y.Length == n);
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x[i] - y[i];
}
return result;
}
public static double[] ElementWiseMinus(double x, double[] y)
{
int n = y.Length;
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x - y[i];
}
return result;
}
public static double[] ElementWiseMultiply(double x, double[] y, double[] z)
{
int n = y.Length;
Debug.Assert(z.Length == n);
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x * y[i] * z[i];
}
return result;
}
public static double[] ElementWiseMultiply(double x, double[] y)
{
int n = y.Length;
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x * y[i];
}
return result;
}
public static double[] ElementWiseDivide(double[] x, double[] y)
{
int n = x.Length;
Debug.Assert(y.Length == n);
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x[i] / y[i];
}
return result;
}
public static double[] ElementWiseAdd(double[] x, double[] y)
{
int n = x.Length;
Debug.Assert(y.Length == n);
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x[i] - y[i];
}
return result;
}
public static double[] ElementWiseAdd(double x, double[] y)
{
int n = y.Length;
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = x + y[i];
}
return result;
}
public static double[] ElementWiseExp(double[] x)
{
int n = x.Length;
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = System.Math.Exp(x[i]);
}
return result;
}
public static double[][] Multiply(double[][] A, double[][] B)
{
int n = A.Length;
int k = A[0].Length;
int m = B[0].Length;
Debug.Assert(B.Length == k);
double[][] result = new double[n][];
for (int row = 0; row < n; ++row)
{
result[row] = new double[m];
double[] rowA = A[row];
for (int col = 0; col < m; ++col)
{
double sum = 0;
for (int num = 0; num < k; ++num)
{
sum += rowA[num] * B[num][col];
}
result[row][col] = sum;
}
}
return result;
}
public static double[] Multiply(double[][] X, double[] beta)
{
Debug.Assert(X[0].Length == beta.Length);
int n = X.Length;
int k = beta.Length;
double[] result = new double[n];
for (int i = 0; i < n; ++i)
{
result[i] = Multiply(X[i], beta);
}
return result;
}
public static double Multiply(double[] x, double[] y)
{
int n = x.Length;
Debug.Assert(y.Length == n);
double sum = 0;
for (int i = 0; i < n; ++i)
{
sum += x[i] * y[i];
}
return sum;
}
/// <summary>
/// The method works by using Gaussian elimination to covert the matrix A to a upper triangular matrix, U, and computes the
/// determinant as the product_i(U_ii) * (-1)^c, where c is the number of row exchange operations that coverts A to U
/// </summary>
/// <param name="A">The matrix for which to calculate determinant</param>
/// <returns>The determinant of A</returns>
public static double GetDeterminant(double[][] A)
{
int ColCount = A[0].Length;
int RowCount = A.Length;
Debug.Assert(ColCount == RowCount);
if (RowCount == 2)
{
return A[0][0] * A[1][1] - A[0][1] * A[1][0];
}
double det = 1;
int rowExchangeOpCount = 0;
double[][] C = GetUpperTriangularMatrix(A, out rowExchangeOpCount);
for (int i = 0; i < RowCount; ++i)
{
det *= C[i][i];
}
return det * (rowExchangeOpCount % 2 == 0 ? 1 : -1);
}
private static double[][] Clone(double[][] A)
{
int rowCount = A.Length;
double[][] clone = new double[rowCount][];
for (int r = 0; r < rowCount; ++r)
{
clone[r] = (double[])A[r].Clone();
}
return clone;
}
public static void GaussianElimination(double[][] A, double[][] Q, double[][] M)
{
int rowCount = A.Length;
int colCount = A[0].Length;
}
public static double[][] GetUpperTriangularMatrix(double[][] A)
{
int rowExchangeOpCount = 0;
return GetUpperTriangularMatrix(A, out rowExchangeOpCount);
}
/// <summary>
/// The method works by using Gaussian elimination to covert the matrix A to a upper triangular matrix
/// The computational Complexity is O(n^3)
/// </summary>
/// <param name="A">The original matrix</param>
/// <returns>The upper triangular matrix</returns>
public static double[][] GetUpperTriangularMatrix(double[][] A, out int rowExchangeOpCount)
{
double[][] B = Clone(A);
int colCount = B[0].Length;
int rowCount = B.Length;
HashSet<int> rows_left = new HashSet<int>();
for (int r = 0; r < rowCount; ++r)
{
rows_left.Add(r);
}
List<int> row_mapping = new List<int>();
for (int r = 0; r < rowCount; ++r)
{
row_mapping.Add(r);
}
rowExchangeOpCount = 0;
List<int> new_rows = new List<int>();
for (int c = 0; c < colCount; ++c)
{
List<int> nonzero_rows = GetRowsWithNonZeroAtColIndex(rows_left, B, c);
if (nonzero_rows.Count > 0)
{
int pivot_row = GetPivotRow(nonzero_rows, B, c);
new_rows.Add(pivot_row);
rows_left.Remove(pivot_row);
for (int i = 0; i < nonzero_rows.Count; ++i)
{
int r = nonzero_rows[i];
if (r != pivot_row)
{
double multiplier = B[r][c] / B[pivot_row][c];
for (int j = c; j < rowCount; ++j)
{
B[r][j] -= B[pivot_row][j] * multiplier;
}
}
}
}
}
foreach (int r in rows_left)
{
new_rows.Add(r);
}
for (int i = 0; i < new_rows.Count; ++i)
{
int new_row = new_rows[i];
int old_row = i;
if (new_row != old_row)
{
double[] temp = B[new_row];
B[new_row] = B[old_row];
B[old_row] = temp;
int new_row_index = i;
int old_row_index = new_rows.IndexOf(old_row);
Swap(new_rows, new_row_index, old_row_index);
rowExchangeOpCount++;
}
}
return B;
}
private static void Swap(List<int> values, int i, int j)
{
int temp = values[i];
values[i] = values[j];
values[j] = temp;
}
private static int GetPivotRow(List<int> rows, double[][] A, int c)
{
double maxValue = double.MinValue;
double val = 0;
int pivot_row = 0;
foreach (int r in rows)
{
val = A[r][c];
if (val > maxValue)
{
maxValue = val;
pivot_row = r;
}
}
return pivot_row;
}
/// <summary>
/// Find all the rows in the row_set such that the row has 0 in its c-th column
/// </summary>
/// <param name="row_set">The set of row indices from which to return the selected rows</param>
/// <param name="A">The matrix containing all rows</param>
/// <param name="c">The targeted column index</param>
/// <returns>The rows in the row_set such that the row has 0 in its c-th column</returns>
private static List<int> GetRowsWithNonZeroAtColIndex(HashSet<int> row_set, double[][] A, int c)
{
List<int> nonzero_rows = new List<int>();
foreach (int r in row_set)
{
if (A[r][c] != 0)
{
nonzero_rows.Add(r);
}
}
return nonzero_rows;
}
public static string Summary(double[][] A)
{
StringBuilder sb = new StringBuilder();
sb.Append("[");
for (int i = 0; i < A.Length; ++i)
{
if (i == A.Length - 1)
{
sb.Append(Summary(A[i]));
}
else
{
sb.AppendLine(Summary(A[i]));
}
}
sb.Append("]");
return sb.ToString();
}
public static string Summary<T>(T[] v)
{
StringBuilder sb = new StringBuilder();
sb.Append("[");
for (int i = 0; i < v.Length; ++i)
{
if (i != 0)
{
sb.Append("\t");
}
sb.AppendFormat("{0:0.00}", v[i]);
}
sb.Append("]");
return sb.ToString();
}
}
}