Files

280 lines
9.2 KiB
C#
Raw Permalink Normal View History

2026-03-25 18:20:24 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CaeGlobals
{
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/july/test-run-matrix-inversion-using-csharp#the-demo-program
// Scale nodes
//if (_currentView == ViewGeometryModelResults.Results && _results.Mesh != null)
//{
// float[] values;
// double[][] deformedCoor;
// float scale = GetScale();
// //
// _results.GetNodesAndValues(_currentFieldData, cellFaceNodeIds, out deformedCoor, out values);
// // A - first cell point
// // B - second cell point
// // C - third cell point
// // P - point
// // A * u + B * v + C * w = P
// double[][] linSys = new double[3][];
// linSys[0] = new double[] { deformedCoor[0][0], deformedCoor[1][0], deformedCoor[2][0] };
// linSys[1] = new double[] { deformedCoor[0][1], deformedCoor[1][1], deformedCoor[2][1] };
// linSys[2] = new double[] { deformedCoor[0][2], deformedCoor[1][2], deformedCoor[2][2] };
// double[][] invLinSys = Matrix.MatrixInverse(linSys);
// //
// double[][] p = new double[][] { new double[] { point[0] }, new double[] { point[1] }, new double[] { point[2] } };
// //
// double[][] uvw = Matrix.MatrixProduct(invLinSys, p);
// //
// double[][] coor;
// _results.GetNodesAndValues(_currentFieldData, cellFaceNodeIds, out coor, out values);
// //
// linSys[0] = new double[] { coor[0][0], coor[1][0], coor[2][0] };
// linSys[1] = new double[] { coor[0][1], coor[1][1], coor[2][1] };
// linSys[2] = new double[] { coor[0][2], coor[1][2], coor[2][2] };
// //
// p = Matrix.MatrixProduct(linSys, uvw);
// //
// point[0] = p[0][0];
// point[1] = p[1][0];
// point[2] = p[2][0];
//}
public class Matrix
{
public static double[][] MatrixInverse(double[][] matrix)
{
// assumes determinant is not 0
// that is, the matrix does have an inverse
int n = matrix.Length;
double[][] result = MatrixCreate(n, n); // make a copy of matrix
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
result[i][j] = matrix[i][j];
double[][] lum; // combined lower & upper
int[] perm;
int toggle;
toggle = MatrixDecompose(matrix, out lum, out perm);
double[] b = new double[n];
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
if (i == perm[j])
b[j] = 1.0;
else
b[j] = 0.0;
double[] x = Helper(lum, b); //
for (int j = 0; j < n; ++j)
result[j][i] = x[j];
}
return result;
} // MatrixInverse
static int MatrixDecompose(double[][] m, out double[][] lum, out int[] perm)
{
// Crout's LU decomposition for matrix determinant and inverse
// stores combined lower & upper in lum[][]
// stores row permuations into perm[]
// returns +1 or -1 according to even or odd number of row permutations
// lower gets dummy 1.0s on diagonal (0.0s above)
// upper gets lum values on diagonal (0.0s below)
int toggle = +1; // even (+1) or odd (-1) row permutatuions
int n = m.Length;
// make a copy of m[][] into result lu[][]
lum = MatrixCreate(n, n);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
lum[i][j] = m[i][j];
// make perm[]
perm = new int[n];
for (int i = 0; i < n; ++i)
perm[i] = i;
for (int j = 0; j < n - 1; ++j) // process by column. note n-1
{
double max = Math.Abs(lum[j][j]);
int piv = j;
for (int i = j + 1; i < n; ++i) // find pivot index
{
double xij = Math.Abs(lum[i][j]);
if (xij > max)
{
max = xij;
piv = i;
}
} // i
if (piv != j)
{
double[] tmp = lum[piv]; // swap rows j, piv
lum[piv] = lum[j];
lum[j] = tmp;
int t = perm[piv]; // swap perm elements
perm[piv] = perm[j];
perm[j] = t;
toggle = -toggle;
}
double xjj = lum[j][j];
if (xjj != 0.0)
{
for (int i = j + 1; i < n; ++i)
{
double xij = lum[i][j] / xjj;
lum[i][j] = xij;
for (int k = j + 1; k < n; ++k)
lum[i][k] -= xij * lum[j][k];
}
}
} // j
return toggle;
} // MatrixDecompose
static double[] Helper(double[][] luMatrix, double[] b) // helper
{
int n = luMatrix.Length;
double[] x = new double[n];
b.CopyTo(x, 0);
for (int i = 1; i < n; ++i)
{
double sum = x[i];
for (int j = 0; j < i; ++j)
sum -= luMatrix[i][j] * x[j];
x[i] = sum;
}
x[n - 1] /= luMatrix[n - 1][n - 1];
for (int i = n - 2; i >= 0; --i)
{
double sum = x[i];
for (int j = i + 1; j < n; ++j)
sum -= luMatrix[i][j] * x[j];
x[i] = sum / luMatrix[i][i];
}
return x;
} // Helper
static double MatrixDeterminant(double[][] matrix)
{
double[][] lum;
int[] perm;
int toggle = MatrixDecompose(matrix, out lum, out perm);
double result = toggle;
for (int i = 0; i < lum.Length; ++i)
result *= lum[i][i];
return result;
}
// ----------------------------------------------------------------
public static double[][] MatrixCreate(int rows, int cols)
{
double[][] result = new double[rows][];
for (int i = 0; i < rows; ++i)
result[i] = new double[cols];
return result;
}
public static double[][] MatrixProduct(double[][] matrixA,
double[][] matrixB)
{
int aRows = matrixA.Length;
int aCols = matrixA[0].Length;
int bRows = matrixB.Length;
int bCols = matrixB[0].Length;
if (aCols != bRows)
throw new Exception("Non-conformable matrices");
double[][] result = MatrixCreate(aRows, bCols);
for (int i = 0; i < aRows; ++i) // each row of A
for (int j = 0; j < bCols; ++j) // each col of B
for (int k = 0; k < aCols; ++k) // could use k < bRows
result[i][j] += matrixA[i][k] * matrixB[k][j];
return result;
}
public static double[][] MatrixTranspose(double[][] matrix)
{
int aRows = matrix.Length;
int aCols = matrix[0].Length;
double[][] result = MatrixCreate(aCols, aRows);
for (int i = 0; i < aRows; ++i) // each row of A
for (int j = 0; j < aCols; ++j) // each col of B
result[j][i] = matrix[i][j];
return result;
}
static string MatrixAsString(double[][] matrix)
{
string s = "";
for (int i = 0; i < matrix.Length; ++i)
{
for (int j = 0; j < matrix[i].Length; ++j)
s += matrix[i][j].ToString("F3").PadLeft(8) + " ";
s += Environment.NewLine;
}
return s;
}
static double[][] ExtractLower(double[][] lum)
{
// lower part of an LU Doolittle decomposition (dummy 1.0s on diagonal, 0.0s above)
int n = lum.Length;
double[][] result = MatrixCreate(n, n);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (i == j)
result[i][j] = 1.0;
else if (i > j)
result[i][j] = lum[i][j];
}
}
return result;
}
static double[][] ExtractUpper(double[][] lum)
{
// upper part of an LU (lu values on diagional and above, 0.0s below)
int n = lum.Length;
double[][] result = MatrixCreate(n, n);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (i <= j)
result[i][j] = lum[i][j];
}
}
return result;
}
}
}