< Summary

Class:Towel.Mathematics.Matrix<T>
Assembly:Towel
File(s):File 1: /home/runner/work/Towel/Towel/Sources/Towel/Mathematics/Matrix.cs
Covered lines:757
Uncovered lines:498
Coverable lines:1255
Total lines:2532
Line coverage:60.3% (757 of 1255)
Covered branches:261
Total branches:503
Branch coverage:51.8% (261 of 503)

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
File 1: get_Length()100%1100%
File 1: get_Rows()100%1100%
File 1: get_Columns()100%1100%
File 1: get_IsSquare()100%1100%
File 1: get_IsVector()100%10%
File 1: get_Is2x1()0%20%
File 1: get_Is3x1()0%20%
File 1: get_Is4x1()0%20%
File 1: get_Is2x2()0%20%
File 1: get_Is3x3()0%20%
File 1: get_Is4x4()0%20%
File 1: get_Item(...)50%855.55%
File 1: set_Item(...)50%855.55%
File 1: get_Item(...)0%40%
File 1: set_Item(...)50%466.66%
File 1: get_DebuggerString()0%100%
File 1: .ctor(...)100%1100%
File 1: .ctor(...)50%466.66%
File 1: .ctor(...)100%1100%
File 1: .ctor(...)100%10%
File 1: .ctor(...)0%40%
File 1: .ctor(...)100%1100%
File 1: .ctor(...)100%10%
File 1: FactoryZero(...)100%4100%
File 1: .cctor()50%1663.63%
File 1: FactoryIdentity(...)100%4100%
File 1: FactoryUniform(...)0%40%
File 1: RowMultiplication(...)0%20%
File 1: RowAddition(...)0%20%
File 1: SwapRows(...)100%10%
File 1: SwapRows(...)100%2100%
File 1: GetCofactor(...)100%10100%
File 1: .ctor(...)100%1100%
File 1: .ctor(...)100%1100%
File 1: get_Value()100%1100%
File 1: op_Addition(...)100%1100%
File 1: op_Multiply(...)100%1100%
File 1: op_UnaryNegation(...)100%1100%
File 1: op_Subtraction(...)100%1100%
File 1: op_Division(...)100%1100%
File 1: op_LessThan(...)50%285.71%
File 1: op_Equality(...)100%2100%
File 1: op_Inequality(...)100%10%
File 1: op_GreaterThan(...)100%2100%
File 1: op_GreaterThanOrEqual(...)100%1100%
File 1: op_LessThanOrEqual(...)0%20%
File 1: op_Explicit(...)100%10%
File 1: Abs()100%1100%
File 1: get_IsDividedByZero()100%1100%
File 1: GetDeterminantGaussian(...)83.33%1890.69%
File 1: GetDeterminantLaplace(...)100%4100%
File 1: GetIsSymetric(...)0%100%
File 1: get_IsSymetric()100%10%
File 1: Negate(...)62.5%873.68%
File 1: Negate(...)100%1100%
File 1: op_UnaryNegation(...)100%1100%
File 1: Negate(...)100%10%
File 1: Negate()100%10%
File 1: Add(...)71.42%1477.27%
File 1: Add(...)100%1100%
File 1: op_Addition(...)100%1100%
File 1: Add(...)100%10%
File 1: Add(...)100%10%
File 1: Subtract(...)71.42%1477.27%
File 1: Subtract(...)100%1100%
File 1: op_Subtraction(...)100%1100%
File 1: Subtract(...)100%10%
File 1: Subtract(...)100%10%
File 1: Multiply(...)79.16%2483.33%
File 1: Multiply(...)100%1100%
File 1: op_Multiply(...)100%1100%
File 1: Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)71.42%1488.88%
File 1: Multiply(...)100%1100%
File 1: op_Multiply(...)100%1100%
File 1: Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)62.5%873.68%
File 1: Multiply(...)100%1100%
File 1: Multiply(...)100%10%
File 1: op_Multiply(...)100%1100%
File 1: op_Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Multiply(...)100%10%
File 1: Divide(...)62.5%873.68%
File 1: Divide(...)100%1100%
File 1: op_Division(...)100%1100%
File 1: Divide(...)100%10%
File 1: Divide(...)100%10%
File 1: Power(...)37.5%2446.15%
File 1: Power(...)100%1100%
File 1: op_ExclusiveOr(...)100%10%
File 1: Power(...)100%10%
File 1: Power(...)100%1100%
File 1: Determinant(...)100%1100%
File 1: DeterminantGaussian(...)75%4100%
File 1: DeterminantLaplace(...)75%4100%
File 1: Determinant()100%10%
File 1: DeterminantLaplace()100%1100%
File 1: DeterminantGaussian()100%1100%
File 1: Trace(...)83.33%6100%
File 1: Trace()100%1100%
File 1: XML_Minor()100%1100%
File 1: Minor(...)100%1100%
File 1: Minor(...)100%1100%
File 1: Minor(...)100%10%
File 1: Minor(...)89.28%2883.72%
File 1: ConcatenateRowWise(...)65%2089.47%
File 1: ConcatenateRowWise(...)100%1100%
File 1: ConcatenateRowWise(...)100%10%
File 1: ConcatenateRowWise(...)100%1100%
File 1: ReducedEchelon(...)80%3084.12%
File 1: ReducedEchelon(...)100%1100%
File 1: ReducedEchelon(...)100%10%
File 1: ReducedEchelon()100%1100%
File 1: Inverse(...)62.5%1670%
File 1: Inverse(...)100%1100%
File 1: Inverse()100%1100%
File 1: Adjoint(...)66.66%1868.75%
File 1: Adjoint(...)100%1100%
File 1: Adjoint(...)100%10%
File 1: Adjoint()100%1100%
File 1: Transpose(...)56.25%1664.28%
File 1: Transpose(...)100%1100%
File 1: Transpose(...)100%10%
File 1: Transpose()100%1100%
File 1: DecomposeLowerUpper(...)0%240%
File 1: DecomposeLowerUpper(...)100%10%
File 1: Rotate4x4(...)0%370%
File 1: Rotate4x4(...)100%10%
File 1: Equal(...)50%1455.55%
File 1: op_Equality(...)100%1100%
File 1: op_Inequality(...)100%10%
File 1: Equal(...)100%10%
File 1: Equal(...)57.14%1462.96%
File 1: Equal(...)100%1100%
File 1: Get(...)100%1100%
File 1: Set(...)100%1100%
File 1: Format(...)100%4100%
File 1: Format(...)100%10%
File 1: CloneContents(...)0%20%
File 1: TransposeContents(...)0%40%
File 1: Clone(...)50%2100%
File 1: Clone()100%1100%
File 1: op_Implicit(...)100%1100%
File 1: op_Explicit(...)0%40%
File 1: GetHashCode()0%20%
File 1: Equals(...)0%20%

File(s)

/home/runner/work/Towel/Towel/Sources/Towel/Mathematics/Matrix.cs

#LineLine coverage
 1using System.Diagnostics;
 2using System.Text;
 3
 4namespace Towel.Mathematics;
 5
 6/// <summary>A matrix of arbitrary dimensions implemented as a flattened array.</summary>
 7/// <typeparam name="T">The numeric type of this Matrix.</typeparam>
 8[DebuggerDisplay("{" + nameof(DebuggerString) + "}")]
 9public class Matrix<T>
 10{
 11  internal readonly T[] _matrix;
 12  internal int _rows;
 13  internal int _columns;
 14
 15  #region Properties
 16
 1117  internal int Length => _matrix.Length;
 18  /// <summary>The number of rows in the matrix.</summary>
 62919  public int Rows => _rows;
 20  /// <summary>The number of columns in the matrix.</summary>
 364221  public int Columns => _columns;
 22  /// <summary>Determines if the matrix is square.</summary>
 3823  public bool IsSquare => _rows == _columns;
 24  /// <summary>Determines if the matrix is a vector.</summary>
 025  public bool IsVector { get { return _columns is 1; } }
 26  /// <summary>Determines if the matrix is a 2 component vector.</summary>
 027  public bool Is2x1 => _rows is 2 && _columns is 1;
 28  /// <summary>Determines if the matrix is a 3 component vector.</summary>
 029  public bool Is3x1 => _rows is 3 && _columns is 1;
 30  /// <summary>Determines if the matrix is a 4 component vector.</summary>
 031  public bool Is4x1 => _rows is 4 && _columns is 1;
 32  /// <summary>Determines if the matrix is a 2 square matrix.</summary>
 033  public bool Is2x2 => _rows is 2 && _columns is 2;
 34  /// <summary>Determines if the matrix is a 3 square matrix.</summary>
 035  public bool Is3x3 => _rows is 3 && _columns is 3;
 36  /// <summary>Determines if the matrix is a 4 square matrix.</summary>
 037  public bool Is4x4 => _rows is 4 && _columns is 4;
 38
 39  /// <summary>Standard row-major matrix indexing.</summary>
 40  /// <param name="row">The row index.</param>
 41  /// <param name="column">The column index.</param>
 42  /// <returns>The value at the given indeces.</returns>
 43  public T this[int row, int column]
 44  {
 45    get
 7646    {
 7647      if (row < 0 || row >= Rows)
 048      {
 049        throw new ArgumentOutOfRangeException(nameof(row), row, "!(" + nameof(row) + " >= 0) || !(" + nameof(row) + " < 
 50      }
 7651      if (column < 0 || column >= Columns)
 052      {
 053        throw new ArgumentOutOfRangeException(nameof(column), row, "!(" + nameof(column) + " >= 0) || !(" + nameof(colum
 54      }
 7655      return Get(row, column);
 7656    }
 57    set
 4558    {
 4559      if (row < 0 || row >= Rows)
 060      {
 061        throw new ArgumentOutOfRangeException(nameof(row), row, "!(" + nameof(row) + " >= 0) || !(" + nameof(row) + " < 
 62      }
 4563      if (column < 0 || column >= Columns)
 064      {
 065        throw new ArgumentOutOfRangeException(nameof(column), row, "!(" + nameof(column) + " >= 0) || !(" + nameof(colum
 66      }
 4567      Set(row, column, value);
 4568    }
 69  }
 70
 71  /// <summary>Indexing of the flattened array representing the matrix.</summary>
 72  /// <param name="flatIndex">The flattened index of the matrix.</param>
 73  /// <returns>The value at the given flattened index.</returns>
 74  public T this[int flatIndex]
 75  {
 76    get
 077    {
 078      if (flatIndex < 0 || _matrix.Length < flatIndex)
 079      {
 080        throw new ArgumentOutOfRangeException(nameof(flatIndex), flatIndex, "!(" + nameof(flatIndex) + " >= 0) || !(" + 
 81      }
 082      return _matrix[flatIndex];
 083    }
 84    set
 985    {
 986      if (flatIndex < 0 || _matrix.Length < flatIndex)
 087      {
 088        throw new ArgumentOutOfRangeException(nameof(flatIndex), flatIndex, "!(" + nameof(flatIndex) + " >= 0) || !(" + 
 89      }
 990      _matrix[flatIndex] = value;
 991    }
 92  }
 93
 94  #endregion
 95
 96  #region Debugger Properties
 97
 98  internal string? DebuggerString
 99  {
 100    get
 0101    {
 0102      if (Rows < 5 && Columns < 5)
 0103      {
 0104        StringBuilder stringBuilder = new();
 0105        stringBuilder.Append('[');
 0106        for (int i = 0; i < Rows; i++)
 0107        {
 0108          stringBuilder.Append('[');
 0109          for (int j = 0; j < Columns; j++)
 0110          {
 0111            stringBuilder.Append(Get(i, j));
 0112            if (j < Columns - 1)
 0113            {
 0114              stringBuilder.Append(',');
 0115            }
 0116          }
 0117          stringBuilder.Append(']');
 0118        }
 0119        stringBuilder.Append(']');
 0120        return stringBuilder.ToString();
 121      }
 0122      return ToString();
 0123    }
 124  }
 125
 126  #endregion
 127
 128  #region Constructors
 129
 57130  internal Matrix(int rows, int columns, int length)
 57131  {
 57132    _matrix = new T[length];
 57133    _rows = rows;
 57134    _columns = columns;
 57135  }
 136
 137  /// <summary>Constructs a new default matrix of the given dimensions.</summary>
 138  /// <param name="rows">The number of row dimensions.</param>
 139  /// <param name="columns">The number of column dimensions.</param>
 284140  public Matrix(int rows, int columns)
 284141  {
 284142    if (rows < 1)
 0143    {
 0144      throw new ArgumentOutOfRangeException(nameof(rows), rows, "!(rows > 0)");
 145    }
 284146    if (columns < 1)
 0147    {
 0148      throw new ArgumentOutOfRangeException(nameof(columns), columns, "!(columns > 0)");
 149    }
 284150    _matrix = new T[rows * columns];
 284151    _rows = rows;
 284152    _columns = columns;
 284153  }
 154
 155  /// <summary>Constructs a new matrix and initializes it via function.</summary>
 156  /// <param name="rows">The number of rows to construct.</param>
 157  /// <param name="columns">The number of columns to construct.</param>
 158  /// <param name="function">The initialization function.</param>
 237159  public Matrix(int rows, int columns, Func<int, int, T> function) : this(rows, columns)
 237160  {
 237161    Format(this, function);
 237162  }
 163
 164  /// <summary>Constructs a new matrix and initializes it via function.</summary>
 165  /// <param name="rows">The number of rows to construct.</param>
 166  /// <param name="columns">The number of columns to construct.</param>
 167  /// <param name="function">The initialization function.</param>
 0168  public Matrix(int rows, int columns, Func<int, T> function) : this(rows, columns)
 0169  {
 0170    Format(this, function);
 0171  }
 172
 173  /// <summary>
 174  /// Creates a new matrix using ROW MAJOR ORDER. The data will be referenced to, so
 175  /// changes to it will modify the constructed matrix.
 176  /// </summary>
 177  /// <param name="rows">The number of rows to construct.</param>
 178  /// <param name="columns">The number of columns to construct.</param>
 179  /// <param name="data">The data of the matrix in ROW MAJOR ORDER.</param>
 0180  public Matrix(int rows, int columns, params T[] data) : this(rows, columns)
 0181  {
 0182    if (data is null) throw new ArgumentNullException(nameof(data));
 0183    if (sourceof(data.Length != rows * columns, out string c1)) throw new ArgumentException(c1);
 0184    _rows = rows;
 0185    _columns = columns;
 0186    _matrix = data;
 0187  }
 188
 16189  internal Matrix(Matrix<T> matrix)
 16190  {
 16191    _rows = matrix._rows;
 16192    _columns = matrix.Columns;
 16193    _matrix = (T[])matrix._matrix.Clone();
 16194  }
 195
 0196  internal Matrix(Vector<T> vector)
 0197  {
 0198    _rows = vector.Dimensions;
 0199    _columns = 1;
 0200    _matrix = (T[])vector._vector.Clone();
 0201  }
 202
 203  #endregion
 204
 205  #region Factories
 206
 207  /// <summary>Constructs a new zero-matrix of the given dimensions.</summary>
 208  /// <param name="rows">The number of rows of the matrix.</param>
 209  /// <param name="columns">The number of columns of the matrix.</param>
 210  /// <returns>The newly constructed zero-matrix.</returns>
 211  public static Matrix<T> FactoryZero(int rows, int columns)
 6212  {
 6213    if (rows < 1)
 1214    {
 1215      throw new ArgumentOutOfRangeException(nameof(rows), rows, "!(" + nameof(rows) + " > 0)");
 216    }
 5217    if (columns < 1)
 1218    {
 1219      throw new ArgumentOutOfRangeException(nameof(columns), columns, "!(" + nameof(columns) + " > 0)");
 220    }
 4221    return FactoryZeroImplementation(rows, columns);
 4222  }
 223
 1224  internal static Func<int, int, Matrix<T>> FactoryZeroImplementation = (rows, columns) =>
 1225  {
 1226    if (Equate(default, Constant<T>.Zero))
 1227    {
 5228      FactoryZeroImplementation = (ROWS, COLUMNS) => new Matrix<T>(ROWS, COLUMNS);
 1229    }
 1230    else
 0231    {
 0232      FactoryZeroImplementation = (ROWS, COLUMNS) =>
 0233      {
 0234        Matrix<T> matrix = new(ROWS, COLUMNS);
 0235        matrix._matrix.Format(Constant<T>.Zero);
 0236        return matrix;
 0237      };
 0238    }
 1239    return FactoryZeroImplementation(rows, columns);
 2240  };
 241
 242  /// <summary>Constructs a new identity-matrix of the given dimensions.</summary>
 243  /// <param name="rows">The number of rows of the matrix.</param>
 244  /// <param name="columns">The number of columns of the matrix.</param>
 245  /// <returns>The newly constructed identity-matrix.</returns>
 246  public static Matrix<T> FactoryIdentity(int rows, int columns)
 6247  {
 6248    if (rows < 1)
 1249    {
 1250      throw new ArgumentOutOfRangeException(nameof(rows), rows, "!(" + nameof(rows) + " > 0)");
 251    }
 5252    if (columns < 1)
 1253    {
 1254      throw new ArgumentOutOfRangeException(nameof(columns), columns, "!(" + nameof(columns) + " > 0)");
 255    }
 4256    return FactoryIdentityImplementation(rows, columns);
 4257  }
 258
 1259  internal static Func<int, int, Matrix<T>> FactoryIdentityImplementation = (rows, columns) =>
 1260  {
 1261    if (Equate(default, Constant<T>.Zero))
 1262    {
 1263      FactoryIdentityImplementation = (ROWS, COLUMNS) =>
 4264      {
 4265        Matrix<T> matrix = new(ROWS, COLUMNS);
 4266        T[] MATRIX = matrix._matrix;
 4267        int minimum = Math.Min(ROWS, COLUMNS);
 28268        for (int i = 0; i < minimum; i++)
 10269        {
 10270          MATRIX[i * COLUMNS + i] = Constant<T>.One;
 10271        }
 4272        return matrix;
 5273      };
 1274    }
 1275    else
 0276    {
 0277      FactoryIdentityImplementation = (ROWS, COLUMNS) =>
 0278      {
 0279        Matrix<T> matrix = new(ROWS, COLUMNS);
 0280        Format(matrix, (x, y) => x == y ? Constant<T>.One : Constant<T>.Zero);
 0281        return matrix;
 0282      };
 0283    }
 1284    return FactoryIdentityImplementation(rows, columns);
 2285  };
 286
 287  /// <summary>Constructs a new matrix where every entry is the same uniform value.</summary>
 288  /// <param name="rows">The number of rows of the matrix.</param>
 289  /// <param name="columns">The number of columns of the matrix.</param>
 290  /// <param name="value">The value to assign every spot in the matrix.</param>
 291  /// <returns>The newly constructed matrix filled with the uniform value.</returns>
 292  public static Matrix<T> FactoryUniform(int rows, int columns, T value)
 0293  {
 0294    if (rows < 1)
 0295    {
 0296      throw new ArgumentOutOfRangeException(nameof(rows), rows, "!(" + nameof(rows) + " > 0)");
 297    }
 0298    if (columns < 1)
 0299    {
 0300      throw new ArgumentOutOfRangeException(nameof(columns), columns, "!(" + nameof(columns) + " > 0)");
 301    }
 0302    Matrix<T> matrix = new(rows, columns);
 0303    matrix._matrix.Format(value);
 0304    return matrix;
 0305  }
 306
 307  #endregion
 308
 309  #region Mathematics
 310
 311  #region RowMultiplication
 312
 313  internal static void RowMultiplication(Matrix<T> matrix, int row, T scalar)
 0314  {
 0315    int columns = matrix.Columns;
 0316    for (int i = 0; i < columns; i++)
 0317    {
 0318      matrix.Set(row, i, Multiplication(matrix.Get(row, i), scalar));
 0319    }
 0320  }
 321
 322  #endregion
 323
 324  #region RowAddition
 325
 326  internal static void RowAddition(Matrix<T> matrix, int target, int second, T scalar)
 0327  {
 0328    int columns = matrix.Columns;
 0329    for (int i = 0; i < columns; i++)
 0330    {
 0331      matrix.Set(target, i, Addition(matrix.Get(target, i), Multiplication(matrix.Get(second, i), scalar)));
 0332    }
 0333  }
 334
 335  #endregion
 336
 337  #region SwapRows
 338
 339  internal static void SwapRows(Matrix<T> matrix, int row1, int row2) =>
 0340    SwapRows(matrix, row1, row2, 0, matrix.Columns - 1);
 341
 342  internal static void SwapRows(Matrix<T> matrix, int row1, int row2, int columnStart, int columnEnd)
 54343  {
 340344    for (int i = columnStart; i <= columnEnd; i++)
 116345    {
 116346      T temp = matrix.Get(row1, i);
 116347      matrix.Set(row1, i, matrix.Get(row2, i));
 116348      matrix.Set(row2, i, temp);
 116349    }
 54350  }
 351
 352  #endregion
 353
 354  #region GetCofactor
 355
 356  internal static void GetCofactor(Matrix<T> a, Matrix<T> temp, int p, int q, int n)
 98357  {
 196358    int i = 0, j = 0;
 720359    for (int row = 0; row < n; row++)
 262360    {
 1968361      for (int col = 0; col < n; col++)
 722362      {
 722363        if (row != p && col != q)
 296364        {
 296365          temp.Set(i, j++, a.Get(row, col));
 296366          if (j == n - 1)
 164367          {
 164368            j = 0;
 164369            i++;
 164370          }
 296371        }
 722372      }
 262373    }
 98374  }
 375
 376  #endregion
 377
 378  #region GetDeterminant Gaussian elimination
 379
 380  #region MatrixElementFraction
 381  /// <summary>
 382  /// Used to avoid issues when 1/2 + 1/2 = 0 + 0 = 0 instead of 1 for types, where division results in precision loss
 383  /// </summary>
 384#pragma warning disable CS0660 // Type defines operator == or operator != but does not override Object.Equals(object o)
 385#pragma warning disable CS0661 // Type defines operator == or operator != but does not override Object.GetHashCode()
 386  private sealed class MatrixElementFraction
 387#pragma warning restore CS0661 // Type defines operator == or operator != but does not override Object.GetHashCode()
 388#pragma warning restore CS0660 // Type defines operator == or operator != but does not override Object.Equals(object o)
 389  {
 390    private readonly T Numerator;
 391    private readonly T Denominator;
 392
 620393    internal MatrixElementFraction(T value)
 620394    {
 620395      Numerator = value;
 620396      Denominator = Constant<T>.One;
 620397    }
 398
 692399    internal MatrixElementFraction(T num, T den)
 692400    {
 692401      Numerator = num;
 692402      Denominator = den;
 692403    }
 404
 64405    public T Value => Division(Numerator, Denominator);
 406
 407    // a / b + c / d = (a * d + b * c) / (b * d)
 408    public static MatrixElementFraction operator +(MatrixElementFraction a, MatrixElementFraction b)
 88409      => new(Addition(
 88410        Multiplication(a.Numerator, b.Denominator),
 88411        Multiplication(a.Denominator, b.Numerator)
 88412      ), Multiplication(a.Denominator, b.Denominator));
 413
 414    public static MatrixElementFraction operator *(MatrixElementFraction a, MatrixElementFraction b)
 222415      => new(Multiplication(a.Numerator, b.Numerator), Multiplication(a.Denominator, b.Denominator));
 416
 417    public static MatrixElementFraction operator -(MatrixElementFraction a)
 142418      => new(Multiplication(a.Numerator, Constant<T>.NegativeOne), a.Denominator);
 419
 420    public static MatrixElementFraction operator -(MatrixElementFraction a, MatrixElementFraction b)
 88421      => a + (-b);
 422
 423    // a / b / (d / c) = (a * c) / (b * d)
 424    public static MatrixElementFraction operator /(MatrixElementFraction a, MatrixElementFraction b)
 88425      => new(Multiplication(a.Numerator, b.Denominator), Multiplication(a.Denominator, b.Numerator));
 426
 427    public static bool operator <(MatrixElementFraction a, MatrixElementFraction b)
 76428    {
 76429      var c = Multiplication(a.Numerator, b.Denominator);
 76430      var d = Multiplication(b.Numerator, a.Denominator);
 76431      if (IsPositive(Multiplication(a.Denominator, b.Denominator)))
 76432        return LessThan(c, d);
 433      else
 0434        return !LessThan(c, d);
 76435    }
 436
 437    public static bool operator ==(MatrixElementFraction a, MatrixElementFraction b) =>
 64438      Equate(a.Numerator, b.Numerator) &&
 64439      Equate(a.Denominator, b.Denominator);
 440    public static bool operator !=(MatrixElementFraction a, MatrixElementFraction b)
 0441      => !(a == b);
 442
 443    public static bool operator >(MatrixElementFraction a, MatrixElementFraction b)
 76444      => a >= b && !(a == b);
 445
 446    public static bool operator >=(MatrixElementFraction a, MatrixElementFraction b)
 76447      => !(a < b);
 448
 449    public static bool operator <=(MatrixElementFraction a, MatrixElementFraction b)
 0450      => a < b || a == b;
 451
 452    public static explicit operator MatrixElementFraction(int val)
 0453      => new(Convert<int, T>(val));
 454
 455    public MatrixElementFraction Abs()
 152456      => new(AbsoluteValue(Numerator), AbsoluteValue(Denominator));
 457
 64458    public bool IsDividedByZero => Equate(Denominator, Constant<T>.Zero);
 459  }
 460  #endregion
 461
 462  // Reference: https://codereview.stackexchange.com/questions/204135/determinant-using-gauss-elimination
 463  internal static T GetDeterminantGaussian(Matrix<T> matrix, int n)
 64464  {
 465    // Note: the reasoning behind using MatrixElementFraction is to account for
 466    // rounding errors such as 2.00...01 instead of 2
 467
 64468    if (n is 1)
 0469    {
 0470      return matrix.Get(0, 0);
 471    }
 64472    MatrixElementFraction determinant = new(Constant<T>.One);
 620473    Matrix<MatrixElementFraction> fractioned = new(matrix.Rows, matrix.Columns, (r, c) => new(matrix.Get(r, c)));
 396474    for (int i = 0; i < n; i++)
 134475    {
 134476      var pivotElement = fractioned.Get(i, i);
 134477      var pivotRow = i;
 420478      for (int row = i + 1; row < n; ++row)
 76479      {
 76480        if (fractioned[row, i].Abs() > pivotElement.Abs())
 58481        {
 58482          pivotElement = fractioned.Get(row, i);
 58483          pivotRow = row;
 58484        }
 76485      }
 134486      if (pivotElement.Equals(Constant<T>.Zero))
 0487      {
 0488        return Constant<T>.Zero;
 489      }
 134490      if (pivotRow != i)
 54491      {
 54492        Matrix<MatrixElementFraction>.SwapRows(fractioned, i, pivotRow, 0, n - 1);
 54493        determinant = Negation(determinant);
 54494      }
 134495      determinant *= pivotElement;
 420496      for (int row = i + 1; row < n; row++)
 76497      {
 328498        for (int column = i + 1; column < n; column++)
 88499        {
 500          // reference: matrix[row][column] -= matrix[row][i] * matrix[i][column] / pivotElement;
 88501          fractioned.Set(row, column,
 88502            // D - A * B / C
 88503            D_subtract_A_multiply_B_divide_C<MatrixElementFraction>.Function(
 88504              /* A */ fractioned.Get(row, i),
 88505              /* B */ fractioned.Get(i, column),
 88506              /* C */ pivotElement,
 88507              /* D */ fractioned.Get(row, column)));
 88508        }
 76509      }
 134510    }
 511#warning TODO: should we return zero if determinant's denominator is zero?
 64512    return determinant.IsDividedByZero ? Constant<T>.Zero : determinant.Value;
 64513  }
 514
 515  #endregion
 516
 517  #region GetDeterminant Laplace method
 518
 519  internal static T GetDeterminantLaplace(Matrix<T> a, int n)
 52520  {
 52521    T determinant = Constant<T>.Zero;
 52522    if (n is 1)
 32523    {
 32524      return a.Get(0, 0);
 525    }
 20526    Matrix<T> temp = new(n, n);
 20527    T sign = Constant<T>.One;
 128528    for (int f = 0; f < n; f++)
 44529    {
 44530      GetCofactor(a, temp, 0, f, n);
 44531      determinant =
 44532        Addition(determinant,
 44533          Multiplication(sign,
 44534            Multiplication(a.Get(0, f),
 44535              GetDeterminantLaplace(temp, n - 1))));
 44536      sign = Negation(sign);
 44537    }
 20538    return determinant;
 52539  }
 540
 541  #endregion
 542
 543  #region IsSymetric
 544
 545  /// <summary>Determines if the matrix is symetric.</summary>
 546  /// <param name="a">The matrix to determine if symetric.</param>
 547  /// <returns>True if the matrix is symetric; false if not.</returns>
 548  public static bool GetIsSymetric(Matrix<T> a)
 0549  {
 0550    if (a is null) throw new ArgumentNullException(nameof(a));
 0551    int rows = a._rows;
 0552    if (rows != a._columns)
 0553    {
 0554      return false;
 555    }
 0556    T[] A = a._matrix;
 0557    for (int row = 0; row < rows; row++)
 0558    {
 0559      for (int column = row + 1; column < rows; column++)
 0560      {
 0561        if (Inequate(A[row * rows + column], A[column * rows + row]))
 0562        {
 0563          return false;
 564        }
 0565      }
 0566    }
 0567    return true;
 0568  }
 569
 570  /// <summary>Determines if the matrix is symetric.</summary>
 571  /// <returns>True if the matrix is symetric; false if not.</returns>
 572  public bool IsSymetric
 573  {
 574    get
 0575    {
 0576      return GetIsSymetric(this);
 0577    }
 578  }
 579
 580  #endregion
 581
 582  #region Negate
 583
 584  /// <summary>Negates all the values in a matrix.</summary>
 585  /// <param name="a">The matrix to have its values negated.</param>
 586  /// <param name="b">The resulting matrix after the negation.</param>
 587  public static void Negate(Matrix<T> a, ref Matrix<T>? b)
 4588  {
 4589    if (a is null) throw new ArgumentNullException(nameof(a));
 4590    int Length = a._matrix.Length;
 4591    T[] A = a._matrix;
 592    T[] B;
 4593    if (b is not null && b._matrix.Length == Length)
 0594    {
 0595      B = b._matrix;
 0596      b._rows = a._rows;
 0597      b._columns = a._columns;
 0598    }
 599    else
 4600    {
 4601      b = new Matrix<T>(a._rows, a._columns, Length);
 4602      B = b._matrix;
 4603    }
 80604    for (int i = 0; i < Length; i++)
 36605    {
 36606      B[i] = Negation(A[i]);
 36607    }
 4608  }
 609
 610  /// <summary>Negates all the values in a matrix.</summary>
 611  /// <param name="a">The matrix to have its values negated.</param>
 612  /// <returns>The resulting matrix after the negation.</returns>
 613  public static Matrix<T> Negate(Matrix<T> a)
 4614  {
 4615    Matrix<T>? b = null;
 4616    Negate(a, ref b);
 4617    return b!;
 4618  }
 619
 620  /// <summary>Negates all the values in a matrix.</summary>
 621  /// <param name="a">The matrix to have its values negated.</param>
 622  /// <returns>The resulting matrix after the negation.</returns>
 623  public static Matrix<T> operator -(Matrix<T> a)
 4624  {
 4625    return Negate(a);
 4626  }
 627
 628  /// <summary>Negates all the values in a matrix.</summary>
 629  /// <param name="b">The resulting matrix after the negation.</param>
 630  public void Negate(ref Matrix<T>? b)
 0631  {
 0632    Negate(this, ref b);
 0633  }
 634
 635  /// <summary>Negates all the values in this matrix.</summary>
 636  /// <returns>The resulting matrix after the negation.</returns>
 637  public Matrix<T> Negate()
 0638  {
 0639    return -this;
 0640  }
 641
 642  #endregion
 643
 644  #region Add
 645
 646  /// <summary>Does standard addition of two matrices.</summary>
 647  /// <param name="a">The left matrix of the addition.</param>
 648  /// <param name="b">The right matrix of the addition.</param>
 649  /// <param name="c">The resulting matrix after the addition.</param>
 650  public static void Add(Matrix<T> a, Matrix<T> b, ref Matrix<T>? c)
 5651  {
 5652    if (a is null) throw new ArgumentNullException(nameof(a));
 5653    if (b is null) throw new ArgumentNullException(nameof(b));
 6654    if (sourceof(a._rows != b._rows || a._columns != b._columns, out string c1)) throw new ArgumentException(c1);
 4655    int Length = a._matrix.Length;
 4656    T[] A = a._matrix;
 4657    T[] B = b._matrix;
 658    T[] C;
 4659    if (c is not null && c._matrix.Length == Length)
 0660    {
 0661      C = c._matrix;
 0662      c._rows = a._rows;
 0663      c._columns = a._columns;
 0664    }
 665    else
 4666    {
 4667      c = new Matrix<T>(a._rows, a._columns, Length);
 4668      C = c._matrix;
 4669    }
 80670    for (int i = 0; i < Length; i++)
 36671    {
 36672      C[i] = Addition(A[i], B[i]);
 36673    }
 4674  }
 675
 676  /// <summary>Does standard addition of two matrices.</summary>
 677  /// <param name="a">The left matrix of the addition.</param>
 678  /// <param name="b">The right matrix of the addition.</param>
 679  /// <returns>The resulting matrix after the addition.</returns>
 680  public static Matrix<T> Add(Matrix<T> a, Matrix<T> b)
 5681  {
 5682    Matrix<T>? c = null;
 5683    Add(a, b, ref c);
 4684    return c!;
 4685  }
 686
 687  /// <summary>Does a standard matrix addition.</summary>
 688  /// <param name="a">The left matrix of the addition.</param>
 689  /// <param name="b">The right matrix of the addition.</param>
 690  /// <returns>The resulting matrix after the addition.</returns>
 691  public static Matrix<T> operator +(Matrix<T> a, Matrix<T> b)
 5692  {
 5693    return Add(a, b);
 4694  }
 695
 696  /// <summary>Does standard addition of two matrices.</summary>
 697  /// <param name="b">The right matrix of the addition.</param>
 698  /// <param name="c">The resulting matrix after the addition.</param>
 699  public void Add(Matrix<T> b, ref Matrix<T>? c)
 0700  {
 0701    Add(this, b, ref c);
 0702  }
 703
 704  /// <summary>Does a standard matrix addition.</summary>
 705  /// <param name="b">The matrix to add to this matrix.</param>
 706  /// <returns>The resulting matrix after the addition.</returns>
 707  public Matrix<T> Add(Matrix<T> b)
 0708  {
 0709    return this + b;
 0710  }
 711
 712  #endregion
 713
 714  #region Subtract
 715
 716  /// <summary>Does a standard matrix subtraction.</summary>
 717  /// <param name="a">The left matrix of the subtraction.</param>
 718  /// <param name="b">The right matrix of the subtraction.</param>
 719  /// <param name="c">The resulting matrix after the subtraction.</param>
 720  public static void Subtract(Matrix<T> a, Matrix<T> b, ref Matrix<T>? c)
 5721  {
 5722    if (a is null) throw new ArgumentNullException(nameof(a));
 5723    if (b is null) throw new ArgumentNullException(nameof(b));
 6724    if (sourceof(a._rows != b._rows || a._columns != b._columns, out string c1)) throw new ArgumentException(c1);
 4725    T[] A = a._matrix;
 4726    T[] B = b._matrix;
 4727    int Length = A.Length;
 728    T[] C;
 4729    if (c is not null && c._matrix.Length == Length)
 0730    {
 0731      C = c._matrix;
 0732      c._rows = a._rows;
 0733      c._columns = a._columns;
 0734    }
 735    else
 4736    {
 4737      c = new Matrix<T>(a._rows, a._columns, Length);
 4738      C = c._matrix;
 4739    }
 80740    for (int i = 0; i < Length; i++)
 36741    {
 36742      C[i] = Subtraction(A[i], B[i]);
 36743    }
 4744  }
 745
 746  /// <summary>Does a standard matrix subtraction.</summary>
 747  /// <param name="a">The left matrix of the subtraction.</param>
 748  /// <param name="b">The right matrix of the subtraction.</param>
 749  /// <returns>The resulting matrix after the subtraction.</returns>
 750  public static Matrix<T> Subtract(Matrix<T> a, Matrix<T> b)
 5751  {
 5752    Matrix<T>? c = null;
 5753    Subtract(a, b, ref c);
 4754    return c!;
 4755  }
 756
 757  /// <summary>Does a standard matrix subtraction.</summary>
 758  /// <param name="a">The left matrix of the subtraction.</param>
 759  /// <param name="b">The right matrix of the subtraction.</param>
 760  /// <returns>The resulting matrix after the subtraction.</returns>
 761  public static Matrix<T> operator -(Matrix<T> a, Matrix<T> b)
 5762  {
 5763    return Subtract(a, b);
 4764  }
 765
 766  /// <summary>Does a standard matrix subtraction.</summary>
 767  /// <param name="b">The right matrix of the subtraction.</param>
 768  /// <param name="c">The resulting matrix after the subtraction.</param>
 769  public void Subtract(Matrix<T> b, ref Matrix<T>? c)
 0770  {
 0771    Subtract(this, b, ref c);
 0772  }
 773
 774  /// <summary>Does a standard matrix subtraction.</summary>
 775  /// <param name="b">The right matrix of the subtraction.</param>
 776  /// <returns>The resulting matrix after the subtraction.</returns>
 777  public Matrix<T> Subtract(Matrix<T> b)
 0778  {
 0779    return this - b;
 0780  }
 781
 782  #endregion
 783
 784  #region Multiply (Matrix * Matrix)
 785
 786  /// <summary>Does a standard (triple for looped) multiplication between matrices.</summary>
 787  /// <param name="a">The left matrix of the multiplication.</param>
 788  /// <param name="b">The right matrix of the multiplication.</param>
 789  /// <param name="c">The resulting matrix of the multiplication.</param>
 790  public static void Multiply(Matrix<T> a, Matrix<T> b, ref Matrix<T>? c)
 18791  {
 18792    if (a is null) throw new ArgumentNullException(nameof(a));
 18793    if (b is null) throw new ArgumentNullException(nameof(b));
 19794    if (sourceof(a._columns != b._rows, out string c1)) throw new ArgumentException(c1);
 795
 17796    if (ReferenceEquals(a, b) && ReferenceEquals(a, c))
 0797    {
 0798      Matrix<T> clone = a.Clone();
 0799      a = clone;
 0800      b = clone;
 0801    }
 17802    else if (ReferenceEquals(a, c))
 8803    {
 8804      a = a.Clone();
 8805    }
 9806    else if (ReferenceEquals(b, c))
 0807    {
 0808      b = b.Clone();
 0809    }
 17810    int c_Rows = a._rows;
 17811    int a_Columns = a._columns;
 17812    int c_Columns = b._columns;
 17813    T[] A = a._matrix;
 17814    T[] B = b._matrix;
 815    T[] C;
 17816    if (c is not null && c._matrix.Length == c_Rows * c_Columns)
 12817    {
 12818      C = c._matrix;
 12819      c._rows = c_Rows;
 12820      c._columns = c_Columns;
 12821    }
 822    else
 5823    {
 5824      c = new Matrix<T>(c_Rows, c_Columns);
 5825      C = c._matrix;
 5826    }
 104827    for (int i = 0; i < c_Rows; i++)
 35828    {
 35829      int i_times_a_Columns = i * a_Columns;
 35830      int i_times_c_Columns = i * c_Columns;
 234831      for (int j = 0; j < c_Columns; j++)
 82832      {
 82833        T sum = Constant<T>.Zero;
 632834        for (int k = 0; k < a_Columns; k++)
 234835        {
 234836          sum = MultiplyAddImplementation<T>.Function(A[i_times_a_Columns + k], B[k * c_Columns + j], sum);
 234837        }
 82838        C[i_times_c_Columns + j] = sum;
 82839      }
 35840    }
 17841  }
 842
 843  /// <summary>Does a standard (triple for looped) multiplication between matrices.</summary>
 844  /// <param name="a">The left matrix of the multiplication.</param>
 845  /// <param name="b">The right matrix of the multiplication.</param>
 846  /// <returns>The resulting matrix of the multiplication.</returns>
 847  public static Matrix<T> Multiply(Matrix<T> a, Matrix<T> b)
 6848  {
 6849    Matrix<T>? c = null;
 6850    Multiply(a, b, ref c);
 5851    return c!;
 5852  }
 853
 854  /// <summary>Does a standard (triple for looped) multiplication between matrices.</summary>
 855  /// <param name="a">The left matrix of the multiplication.</param>
 856  /// <param name="b">The right matrix of the multiplication.</param>
 857  /// <returns>The resulting matrix of the multiplication.</returns>
 858  public static Matrix<T> operator *(Matrix<T> a, Matrix<T> b)
 6859  {
 6860    return Multiply(a, b);
 5861  }
 862
 863  /// <summary>Does a standard (triple for looped) multiplication between matrices.</summary>
 864  /// <param name="b">The right matrix of the multiplication.</param>
 865  /// <param name="c">The resulting matrix of the multiplication.</param>
 866  public void Multiply(Matrix<T> b, ref Matrix<T>? c)
 0867  {
 0868    Multiply(this, b, ref c);
 0869  }
 870
 871  /// <summary>Does a standard (triple for looped) multiplication between matrices.</summary>
 872  /// <param name="b">The right matrix of the multiplication.</param>
 873  /// <returns>The resulting matrix of the multiplication.</returns>
 874  public Matrix<T> Multiply(Matrix<T> b)
 0875  {
 0876    return this * b;
 0877  }
 878
 879  #endregion
 880
 881  #region Multiply (Matrix * Vector)
 882
 883  /// <summary>Does a matrix-vector multiplication.</summary>
 884  /// <param name="a">The left matrix of the multiplication.</param>
 885  /// <param name="b">The right vector of the multiplication.</param>
 886  /// <param name="c">The resulting vector of the multiplication.</param>
 887  public static void Multiply(Matrix<T> a, Vector<T> b, ref Vector<T>? c)
 5888  {
 5889    if (a is null) throw new ArgumentNullException(nameof(a));
 5890    if (b is null) throw new ArgumentNullException(nameof(b));
 5891    int rows = a._rows;
 5892    int columns = a._columns;
 6893    if (sourceof(columns != b.Dimensions, out string c1)) throw new ArgumentException(c1);
 4894    T[] A = a._matrix;
 4895    T[] B = b._vector;
 896    T[] C;
 4897    if (c is not null && c.Dimensions == columns)
 0898    {
 0899      C = c._vector;
 0900    }
 901    else
 4902    {
 4903      c = new Vector<T>(columns);
 4904      C = c._vector;
 4905    }
 32906    for (int i = 0; i < rows; i++)
 12907    {
 12908      int i_times_columns = i * columns;
 12909      T sum = Constant<T>.Zero;
 96910      for (int j = 0; j < columns; j++)
 36911      {
 36912        sum = Addition(sum, Multiplication(A[i_times_columns + j], B[j]));
 36913      }
 12914      C[i] = sum;
 12915    }
 4916  }
 917
 918  /// <summary>Does a matrix-vector multiplication.</summary>
 919  /// <param name="a">The left matrix of the multiplication.</param>
 920  /// <param name="b">The right vector of the multiplication.</param>
 921  /// <returns>The resulting vector of the multiplication.</returns>
 922  public static Vector<T> Multiply(Matrix<T> a, Vector<T> b)
 5923  {
 5924    Vector<T>? c = null;
 5925    Multiply(a, b, ref c);
 4926    return c!;
 4927  }
 928
 929  /// <summary>Does a matrix-vector multiplication.</summary>
 930  /// <param name="a">The left matrix of the multiplication.</param>
 931  /// <param name="b">The right vector of the multiplication.</param>
 932  /// <returns>The resulting vector of the multiplication.</returns>
 933  public static Vector<T> operator *(Matrix<T> a, Vector<T> b)
 5934  {
 5935    return Multiply(a, b);
 4936  }
 937
 938  /// <summary>Does a matrix-vector multiplication.</summary>
 939  /// <param name="b">The right vector of the multiplication.</param>
 940  /// <param name="c">The resulting vector of the multiplication.</param>
 941  public void Multiply(Vector<T> b, ref Vector<T>? c)
 0942  {
 0943    Multiply(this, b, ref c);
 0944  }
 945
 946  /// <summary>Does a matrix-vector multiplication.</summary>
 947  /// <param name="b">The right vector of the multiplication.</param>
 948  /// <returns>The resulting vector of the multiplication.</returns>
 949  public Vector<T> Multiply(Vector<T> b)
 0950  {
 0951    return this * b;
 0952  }
 953
 954  #endregion
 955
 956  #region Multiply (Matrix * Scalar)
 957
 958  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 959  /// <param name="a">The matrix to have the values multiplied.</param>
 960  /// <param name="b">The scalar to multiply the values by.</param>
 961  /// <param name="c">The resulting matrix after the multiplications.</param>
 962  public static void Multiply(Matrix<T> a, T b, ref Matrix<T>? c)
 4963  {
 4964    if (a is null) throw new ArgumentNullException(nameof(a));
 4965    T[] A = a._matrix;
 4966    int Length = A.Length;
 967    T[] C;
 4968    if (c is not null && c._matrix.Length == Length)
 0969    {
 0970      C = c._matrix;
 0971      c._rows = a._rows;
 0972      c._columns = a._columns;
 0973    }
 974    else
 4975    {
 4976      c = new Matrix<T>(a._rows, a._columns, Length);
 4977      C = c._matrix;
 4978    }
 80979    for (int i = 0; i < Length; i++)
 36980    {
 36981      C[i] = Multiplication(A[i], b);
 36982    }
 4983  }
 984
 985  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 986  /// <param name="a">The matrix to have the values multiplied.</param>
 987  /// <param name="b">The scalar to multiply the values by.</param>
 988  /// <returns>The resulting matrix after the multiplications.</returns>
 989  public static Matrix<T> Multiply(Matrix<T> a, T b)
 4990  {
 4991    Matrix<T>? c = null;
 4992    Multiply(a, b, ref c);
 4993    return c!;
 4994  }
 995
 996  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 997  /// <param name="b">The scalar to multiply the values by.</param>
 998  /// <param name="a">The matrix to have the values multiplied.</param>
 999  /// <returns>The resulting matrix after the multiplications.</returns>
 1000  public static Matrix<T> Multiply(T b, Matrix<T> a)
 01001  {
 01002    return Multiply(a, b);
 01003  }
 1004
 1005  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 1006  /// <param name="a">The matrix to have the values multiplied.</param>
 1007  /// <param name="b">The scalar to multiply the values by.</param>
 1008  /// <returns>The resulting matrix after the multiplications.</returns>
 1009  public static Matrix<T> operator *(Matrix<T> a, T b)
 41010  {
 41011    return Multiply(a, b);
 41012  }
 1013
 1014  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 1015  /// <param name="b">The scalar to multiply the values by.</param>
 1016  /// <param name="a">The matrix to have the values multiplied.</param>
 1017  /// <returns>The resulting matrix after the multiplications.</returns>
 1018  public static Matrix<T> operator *(T b, Matrix<T> a)
 01019  {
 01020    return Multiply(b, a);
 01021  }
 1022
 1023  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 1024  /// <param name="b">The scalar to multiply the values by.</param>
 1025  /// <param name="c">The resulting matrix after the multiplications.</param>
 1026  public void Multiply(T b, ref Matrix<T>? c)
 01027  {
 01028    Multiply(this, b, ref c);
 01029  }
 1030
 1031  /// <summary>Multiplies all the values in a matrix by a scalar.</summary>
 1032  /// <param name="b">The scalar to multiply the values by.</param>
 1033  /// <returns>The resulting matrix after the multiplications.</returns>
 1034  public Matrix<T> Multiply(T b)
 01035  {
 01036    return this * b;
 01037  }
 1038
 1039  #endregion
 1040
 1041  #region Divide (Matrix / Scalar)
 1042
 1043  /// <summary>Divides all the values in the matrix by a scalar.</summary>
 1044  /// <param name="a">The matrix to divide the values of.</param>
 1045  /// <param name="b">The scalar to divide all the matrix values by.</param>
 1046  /// <param name="c">The resulting matrix after the division.</param>
 1047  public static void Divide(Matrix<T> a, T b, ref Matrix<T>? c)
 41048  {
 41049    if (a is null) throw new ArgumentNullException(nameof(a));
 41050    T[] A = a._matrix;
 41051    int Length = A.Length;
 1052    T[] C;
 41053    if (c is not null && c._matrix.Length == Length)
 01054    {
 01055      C = c._matrix;
 01056      c._rows = a._rows;
 01057      c._columns = a._columns;
 01058    }
 1059    else
 41060    {
 41061      c = new Matrix<T>(a._rows, a._columns, Length);
 41062      C = c._matrix;
 41063    }
 801064    for (int i = 0; i < Length; i++)
 361065    {
 361066      C[i] = Division(A[i], b);
 361067    }
 41068  }
 1069
 1070  /// <summary>Divides all the values in the matrix by a scalar.</summary>
 1071  /// <param name="a">The matrix to divide the values of.</param>
 1072  /// <param name="b">The scalar to divide all the matrix values by.</param>
 1073  /// <returns>The resulting matrix after the division.</returns>
 1074  public static Matrix<T> Divide(Matrix<T> a, T b)
 41075  {
 41076    Matrix<T>? c = null;
 41077    Divide(a, b, ref c);
 41078    return c!;
 41079  }
 1080
 1081  /// <summary>Divides all the values in the matrix by a scalar.</summary>
 1082  /// <param name="a">The matrix to divide the values of.</param>
 1083  /// <param name="b">The scalar to divide all the matrix values by.</param>
 1084  /// <returns>The resulting matrix after the division.</returns>
 1085  public static Matrix<T> operator /(Matrix<T> a, T b)
 41086  {
 41087    return Divide(a, b);
 41088  }
 1089
 1090  /// <summary>Divides all the values in the matrix by a scalar.</summary>
 1091  /// <param name="b">The scalar to divide all the matrix values by.</param>
 1092  /// <param name="c">The resulting matrix after the division.</param>
 1093  public void Divide(T b, ref Matrix<T>? c)
 01094  {
 01095    Divide(this, b, ref c);
 01096  }
 1097
 1098  /// <summary>Divides all the values in the matrix by a scalar.</summary>
 1099  /// <param name="b">The scalar to divide all the matrix values by.</param>
 1100  /// <returns>The resulting matrix after the division.</returns>
 1101  public Matrix<T> Divide(T b)
 01102  {
 01103    return this / b;
 01104  }
 1105
 1106  #endregion
 1107
 1108  #region Power (Matrix ^ Scalar)
 1109
 1110  /// <summary>Applies a power to a square matrix.</summary>
 1111  /// <param name="a">The matrix to be powered by.</param>
 1112  /// <param name="b">The power to apply to the matrix.</param>
 1113  /// <param name="c">The resulting matrix of the power operation.</param>
 1114  public static void Power(Matrix<T> a, int b, ref Matrix<T>? c)
 51115  {
 51116    if (a is null) throw new ArgumentNullException(nameof(a));
 61117    if (sourceof(!a.IsSquare, out string c1)) throw new ArgumentException(c1);
 41118    if (sourceof(b < 0, out string c2)) throw new ArgumentOutOfRangeException(nameof(b), b, c2);
 41119    if (b is 0)
 01120    {
 01121      if (c is not null && c._matrix.Length == a._matrix.Length)
 01122      {
 01123        c._rows = a._rows;
 01124        c._columns = a._columns;
 01125        Format(c, (x, y) => x == y ? Constant<T>.One : Constant<T>.Zero);
 01126      }
 1127      else
 01128      {
 01129        c = Matrix<T>.FactoryIdentity(a._rows, a._columns);
 01130      }
 01131      return;
 1132    }
 41133    if (c is not null && c._matrix.Length == a._matrix.Length)
 01134    {
 01135      c._rows = a._rows;
 01136      c._columns = a._columns;
 01137      T[] A = a._matrix;
 01138      T[] C = c._matrix;
 01139      for (int i = 0; i < a._matrix.Length; i++)
 01140      {
 01141        C[i] = A[i];
 01142      }
 01143    }
 1144    else
 41145    {
 41146      c = a.Clone();
 41147    }
 41148    Matrix<T>? d = new(a._rows, a._columns, a._matrix.Length);
 321149    for (int i = 0; i < b; i++)
 121150    {
 121151      Multiply(c, a, ref d);
 121152      Matrix<T>? temp = d;
 121153      d = c;
 121154      c = d;
 121155    }
 41156  }
 1157
 1158  /// <summary>Applies a power to a square matrix.</summary>
 1159  /// <param name="a">The matrix to be powered by.</param>
 1160  /// <param name="b">The power to apply to the matrix.</param>
 1161  /// <returns>The resulting matrix of the power operation.</returns>
 1162  public static Matrix<T> Power(Matrix<T> a, int b)
 51163  {
 51164    Matrix<T>? c = null;
 51165    Power(a, b, ref c);
 41166    return c!;
 41167  }
 1168
 1169  /// <summary>Applies a power to a square matrix.</summary>
 1170  /// <param name="a">The matrix to be powered by.</param>
 1171  /// <param name="b">The power to apply to the matrix.</param>
 1172  /// <returns>The resulting matrix of the power operation.</returns>
 1173  [Obsolete("Please use the Power method. The ^ operator in C# does not follow the mathematical order of operations.", t
 1174  public static Matrix<T> operator ^(Matrix<T> a, int b)
 01175  {
 01176    return Power(a, b);
 01177  }
 1178
 1179  /// <summary>Applies a power to a square matrix.</summary>
 1180  /// <param name="b">The power to apply to the matrix.</param>
 1181  /// <param name="c">The resulting matrix of the power operation.</param>
 1182  public void Power(int b, ref Matrix<T>? c)
 01183  {
 01184    Power(this, b, ref c);
 01185  }
 1186
 1187  /// <summary>Applies a power to a square matrix.</summary>
 1188  /// <param name="b">The power to apply to the matrix.</param>
 1189  /// <returns>The resulting matrix of the power operation.</returns>
 1190  public Matrix<T> Power(int b)
 51191  {
 51192    return Power(this, b);
 41193  }
 1194
 1195  #endregion
 1196
 1197  #region Determinant
 1198
 1199  /// <summary>Computes the determinant of a square matrix.</summary>
 1200  /// <param name="a">The matrix to compute the determinant of.</param>
 1201  /// <returns>The computed determinant.</returns>
 1202  public static T Determinant(Matrix<T> a)
 21203  {
 21204    return DeterminantGaussian(a);
 1205
 1206    #region Old Version
 1207
 1208    // if (a is null)
 1209    // {
 1210    //     throw new ArgumentNullException(nameof(a));
 1211    // }
 1212    // if (!a.IsSquare)
 1213    // {
 1214    //     throw new MathematicsException("Argument invalid !(" + nameof(a) + "." + nameof(a.IsSquare) + ")");
 1215    // }
 1216    // T determinant = Constant<T>.One;
 1217    // Matrix<T> rref = a.Clone();
 1218    // int a_rows = a._rows;
 1219    // for (int i = 0; i < a_rows; i++)
 1220    // {
 1221    //     if (Compute.Equal(rref[i, i], Constant<T>.Zero))
 1222    //     {
 1223    //         for (int j = i + 1; j < rref.Rows; j++)
 1224    //         {
 1225    //             if (Compute.NotEqual(rref.Get(j, i), Constant<T>.Zero))
 1226    //             {
 1227    //                 SwapRows(rref, i, j);
 1228    //                 determinant = Compute.Multiply(determinant, Constant<T>.NegativeOne);
 1229    //             }
 1230    //         }
 1231    //     }
 1232    //     determinant = Compute.Multiply(determinant, rref.Get(i, i));
 1233    //     T temp_rowMultiplication = Compute.Divide(Constant<T>.One, rref.Get(i, i));
 1234    //     RowMultiplication(rref, i, temp_rowMultiplication);
 1235    //     for (int j = i + 1; j < rref.Rows; j++)
 1236    //     {
 1237    //         T scalar = Compute.Negate(rref.Get(j, i));
 1238    //         RowAddition(rref, j, i, scalar);
 1239    //     }
 1240    //     for (int j = i - 1; j >= 0; j--)
 1241    //     {
 1242    //         T scalar = Compute.Negate(rref.Get(j, i));
 1243    //         RowAddition(rref, j, i, scalar);
 1244    //     }
 1245    // }
 1246    // return determinant;
 1247
 1248    #endregion
 1249
 21250  }
 1251
 1252  /// <summary>
 1253  /// Computes the determinant of a square matrix via Gaussian elimination.<br/>
 1254  /// Runtime: O((n^3 + 2n^−3) / 3)
 1255  /// </summary>
 1256  /// <param name="a">The matrix to compute the determinant of.</param>
 1257  /// <returns>The computed determinant.</returns>
 1258  public static T DeterminantGaussian(Matrix<T> a)
 111259  {
 111260    if (a is null) throw new ArgumentNullException(nameof(a));
 121261    if (sourceof(!a.IsSquare, out string c1)) throw new ArgumentException(c1);
 101262    return GetDeterminantGaussian(a, a.Rows);
 101263  }
 1264
 1265  /// <summary>
 1266  /// Computes the determinant of a square matrix via Laplace's method.<br/>
 1267  /// Runtime: O(n(2^(n âˆ’ 1) âˆ’ 1))
 1268  /// </summary>
 1269  /// <param name="a">The matrix to compute the determinant of.</param>
 1270  /// <returns>The computed determinant.</returns>
 1271  public static T DeterminantLaplace(Matrix<T> a)
 91272  {
 91273    if (a is null) throw new ArgumentNullException(nameof(a));
 101274    if (sourceof(!a.IsSquare, out string c1)) throw new ArgumentException(c1);
 81275    return GetDeterminantLaplace(a, a.Rows);
 81276  }
 1277
 1278  /// <summary>Computes the determinant of a square matrix.</summary>
 1279  /// <returns>The computed determinant.</returns>
 1280  public T Determinant()
 01281  {
 01282    return DeterminantGaussian(this);
 01283  }
 1284
 1285  /// <summary>Computes the determinant of a square matrix via Laplace's method.</summary>
 1286  /// <returns>The computed determinant.</returns>
 1287  public T DeterminantLaplace()
 91288  {
 91289    return DeterminantLaplace(this);
 81290  }
 1291
 1292  /// <summary>Computes the determinant of a square matrix via Gaussian elimination.</summary>
 1293  /// <returns>The computed determinant.</returns>
 1294  public T DeterminantGaussian()
 91295  {
 91296    return DeterminantGaussian(this);
 81297  }
 1298
 1299  #endregion
 1300
 1301  #region Trace
 1302
 1303  /// <summary>Computes the trace of a square matrix.</summary>
 1304  /// <param name="a">The matrix to compute the trace of.</param>
 1305  /// <returns>The computed trace.</returns>
 1306  public static T Trace(Matrix<T> a)
 51307  {
 51308    if (a is null) throw new ArgumentNullException(nameof(a));
 61309    if (sourceof(!a.IsSquare, out string c1)) throw new ArgumentException(c1);
 41310    T trace = Addition((Action<T> step) =>
 41311    {
 41312      T[] A = a._matrix;
 41313      int rows = a.Rows;
 321314      for (int i = 0; i < rows; i++)
 121315      {
 121316        step(A[i * rows + i]);
 121317      }
 81318    });
 41319    return trace;
 41320  }
 1321
 1322  /// <summary>Computes the trace of a square matrix.</summary>
 1323  /// <returns>The computed trace.</returns>
 1324  public T Trace()
 51325  {
 51326    return Trace(this);
 41327  }
 1328
 1329  #endregion
 1330
 1331  #region Minor
 1332
 1333#pragma warning disable CS1572, SA1625, SA1617
 1334
 1335  /// <summary>Gets the minor of a matrix.</summary>
 1336  /// <param name="a">The matrix to get the minor of.</param>
 1337  /// <param name="row">The restricted row to form the minor.</param>
 1338  /// <param name="column">The restricted column to form the minor.</param>
 1339  /// <param name="b">The minor of the matrix.</param>
 1340  /// <returns>The minor of the matrix.</returns>
 1341  [Obsolete(NotIntended, true)]
 11342  public static void XML_Minor() => throw new DocumentationMethodException();
 1343
 1344#pragma warning restore CS1572, SA1625, SA1617
 1345
 1346  /// <inheritdoc cref="XML_Minor"/>
 1347  public Matrix<T> Minor(int row, int column) =>
 261348    Minor(this, row, column);
 1349
 1350  /// <inheritdoc cref="XML_Minor"/>
 1351  public static Matrix<T> Minor(Matrix<T> a, int row, int column)
 271352  {
 271353    Matrix<T>? b = null;
 271354    Minor(a, row, column, ref b);
 131355    return b!;
 131356  }
 1357
 1358  /// <inheritdoc cref="XML_Minor"/>
 1359  public void Minor(int row, int column, ref Matrix<T>? b) =>
 01360    Minor(this, row, column, ref b);
 1361
 1362  /// <inheritdoc cref="XML_Minor"/>
 1363  public static void Minor(Matrix<T> a, int row, int column, ref Matrix<T>? b)
 271364  {
 281365    if (a is null) throw new ArgumentNullException(nameof(a));
 271366    if (sourceof(a._rows < 2 || a._columns < 2, out string c1)) throw new ArgumentException(c1);
 331367    if (sourceof(!(0 <= row && row < a._rows), out string c2)) throw new ArgumentOutOfRangeException(nameof(row), row, c
 211368    if (sourceof(!(0 <= column && column < a._columns), out string c3)) throw new ArgumentOutOfRangeException(nameof(col
 131369    if (ReferenceEquals(a, b))
 01370    {
 01371      a = a.Clone();
 01372    }
 131373    int a_rows = a._rows;
 131374    int a_columns = a._columns;
 131375    int b_rows = a_rows - 1;
 131376    int b_columns = a_columns - 1;
 131377    int b_length = b_rows * b_columns;
 131378    if (b is null || b._matrix.Length != b_length)
 131379    {
 131380      b = new Matrix<T>(b_rows, b_columns, b_length);
 131381    }
 1382    else
 01383    {
 01384      b._rows = b_rows;
 01385      b._columns = b_columns;
 01386    }
 131387    T[] B = b._matrix;
 131388    T[] A = a._matrix;
 1091389    for (int i = 0, m = 0; i < a_rows; i++)
 351390    {
 351391      if (i == row)
 131392      {
 131393        continue;
 1394      }
 221395      int i_times_a_columns = i * a_columns;
 221396      int m_times_b_columns = m * b_columns;
 1901397      for (int j = 0, n = 0; j < a_columns; j++)
 621398      {
 621399        if (j == column)
 221400        {
 221401          continue;
 1402        }
 401403        T temp = A[i_times_a_columns + j];
 401404        B[m_times_b_columns + n] = temp;
 401405        n++;
 401406      }
 221407      m++;
 221408    }
 131409  }
 1410
 1411  #endregion
 1412
 1413  #region ConcatenateRowWise
 1414
 1415  /// <summary>Combines two matrices from left to right
 1416  /// (result.Rows = left.Rows AND result.Columns = left.Columns + right.Columns).</summary>
 1417  /// <param name="a">The left matrix of the concatenation.</param>
 1418  /// <param name="b">The right matrix of the concatenation.</param>
 1419  /// <param name="c">The resulting matrix of the concatenation.</param>
 1420  public static void ConcatenateRowWise(Matrix<T> a, Matrix<T> b, ref Matrix<T>? c)
 31421  {
 31422    if (a is null) throw new ArgumentNullException(nameof(a));
 31423    if (b is null) throw new ArgumentNullException(nameof(b));
 31424    if (sourceof(a.Rows != b.Rows, out string c1)) throw new ArgumentException(c1);
 31425    int c_rows = a._rows;
 31426    int c_columns = a._columns + b._columns;
 31427    int c_length = c_rows * c_columns;
 31428    if (c is null ||
 31429      c._matrix.Length != c_length ||
 31430      object.ReferenceEquals(a, c) ||
 31431      object.ReferenceEquals(b, c))
 31432    {
 31433      c = new Matrix<T>(c_rows, c_columns, c_length);
 31434    }
 1435    else
 01436    {
 01437      c._rows = c_rows;
 01438      c._columns = c_columns;
 01439    }
 31440    T[] A = a._matrix;
 31441    T[] B = b._matrix;
 31442    T[] C = c._matrix;
 201443    for (int i = 0; i < c_rows; i++)
 71444    {
 71445      int i_times_a_columns = i * a.Columns;
 71446      int i_times_b_columns = i * b.Columns;
 71447      int i_times_c_columns = i * c_columns;
 881448      for (int j = 0; j < c_columns; j++)
 371449      {
 371450        if (j < a.Columns)
 191451        {
 191452          C[i_times_c_columns + j] = A[i_times_a_columns + j];
 191453        }
 1454        else
 181455        {
 181456          C[i_times_c_columns + j] = B[i_times_b_columns + j - a.Columns];
 181457        }
 371458      }
 71459    }
 31460  }
 1461
 1462  /// <summary>Combines two matrices from left to right
 1463  /// (result.Rows = left.Rows AND result.Columns = left.Columns + right.Columns).</summary>
 1464  /// <param name="a">The left matrix of the concatenation.</param>
 1465  /// <param name="b">The right matrix of the concatenation.</param>
 1466  /// <returns>The resulting matrix of the concatenation.</returns>
 1467  public static Matrix<T> ConcatenateRowWise(Matrix<T> a, Matrix<T> b)
 31468  {
 31469    Matrix<T>? c = null;
 31470    ConcatenateRowWise(a, b, ref c);
 31471    return c!;
 31472  }
 1473
 1474  /// <summary>Combines two matrices from left to right
 1475  /// (result.Rows = left.Rows AND result.Columns = left.Columns + right.Columns).</summary>
 1476  /// <param name="b">The right matrix of the concatenation.</param>
 1477  /// <param name="c">The resulting matrix of the concatenation.</param>
 1478  public void ConcatenateRowWise(Matrix<T> b, ref Matrix<T>? c)
 01479  {
 01480    ConcatenateRowWise(this, b, ref c);
 01481  }
 1482
 1483  /// <summary>Combines two matrices from left to right
 1484  /// (result.Rows = left.Rows AND result.Columns = left.Columns + right.Columns).</summary>
 1485  /// <param name="b">The right matrix of the concatenation.</param>
 1486  /// <returns>The resulting matrix of the concatenation.</returns>
 1487  public Matrix<T> ConcatenateRowWise(Matrix<T> b)
 31488  {
 31489    return ConcatenateRowWise(this, b);
 31490  }
 1491
 1492  #endregion
 1493
 1494  #region Echelon
 1495
 1496#if false
 1497
 1498    /// <summary>Calculates the echelon of a matrix (aka REF).</summary>
 1499    /// <param name="a">The matrix to calculate the echelon of (aka REF).</param>
 1500    /// <param name="b">The echelon of the matrix (aka REF).</param>
 1501    /// <bug>Failing for non-floating point rational types due to zero how values are being compared.</bug>
 1502    public static void Echelon(Matrix<T> a, ref Matrix<T> b)
 1503    {
 1504      if (a is null) throw new ArgumentNullException(nameof(a));
 1505      if (ReferenceEquals(a, b))
 1506      {
 1507        a = a.Clone();
 1508      }
 1509      int Rows = a.Rows;
 1510      if (b is not null && b._matrix.Length == a._matrix.Length)
 1511      {
 1512        b._rows = Rows;
 1513        b._columns = a._columns;
 1514        CloneContents(a, b);
 1515      }
 1516      else
 1517      {
 1518        b = a.Clone();
 1519      }
 1520      for (int i = 0; i < Rows; i++)
 1521      {
 1522        if (Equality(b.Get(i, i), Constant<T>.Zero))
 1523        {
 1524          for (int j = i + 1; j < Rows; j++)
 1525          {
 1526            if (Inequality(b.Get(j, i), Constant<T>.Zero))
 1527            {
 1528              SwapRows(b, i, j);
 1529            }
 1530          }
 1531        }
 1532        if (Equality(b.Get(i, i), Constant<T>.Zero))
 1533        {
 1534          continue;
 1535        }
 1536        if (Inequality(b.Get(i, i), Constant<T>.One))
 1537        {
 1538          for (int j = i + 1; j < Rows; j++)
 1539          {
 1540            if (Equality(b.Get(j, i), Constant<T>.One))
 1541            {
 1542              SwapRows(b, i, j);
 1543            }
 1544          }
 1545        }
 1546        T rowMultipier = Division(Constant<T>.One, b.Get(i, i));
 1547        RowMultiplication(b, i, rowMultipier);
 1548        for (int j = i + 1; j < Rows; j++)
 1549        {
 1550          T rowAddend = Negation(b.Get(j, i));
 1551          RowAddition(b, j, i, rowAddend);
 1552        }
 1553      }
 1554    }
 1555
 1556    /// <summary>Calculates the echelon of a matrix (aka REF).</summary>
 1557    /// <param name="a">The matrix to calculate the echelon of (aka REF).</param>
 1558    /// <returns>The echelon of the matrix (aka REF).</returns>
 1559    public static Matrix<T> Echelon(Matrix<T> a)
 1560    {
 1561      Matrix<T> b = null;
 1562      Echelon(a, ref b);
 1563      return b;
 1564    }
 1565
 1566    /// <summary>Calculates the echelon of a matrix (aka REF).</summary>
 1567    /// <param name="b">The echelon of the matrix (aka REF).</param>
 1568    public void Echelon(ref Matrix<T> b)
 1569    {
 1570      Echelon(this, ref b);
 1571    }
 1572
 1573    /// <summary>Calculates the echelon of a matrix (aka REF).</summary>
 1574    /// <returns>The echelon of the matrix (aka REF).</returns>
 1575    public Matrix<T> Echelon()
 1576    {
 1577      return Echelon(this);
 1578    }
 1579
 1580#endif
 1581
 1582  #endregion
 1583
 1584  #region ReducedEchelon
 1585
 1586  /// <summary>Calculates the echelon of a matrix and reduces it (aka RREF).</summary>
 1587  /// <param name="a">The matrix matrix to calculate the reduced echelon of (aka RREF).</param>
 1588  /// <param name="b">The reduced echelon of the matrix (aka RREF).</param>
 1589  public static void ReducedEchelon(Matrix<T> a, ref Matrix<T>? b)
 41590  {
 41591    if (a is null) throw new ArgumentNullException(nameof(a));
 41592    int Rows = a.Rows;
 41593    int Columns = a.Columns;
 41594    if (object.ReferenceEquals(a, b))
 01595    {
 01596      b = a.Clone();
 01597    }
 41598    else if (b is not null && b._matrix.Length == a._matrix.Length)
 01599    {
 01600      b._rows = Rows;
 01601      b._columns = a._columns;
 01602      CloneContents(a, b);
 01603    }
 1604    else
 41605    {
 41606      b = a.Clone();
 41607    }
 41608    int lead = 0;
 321609    for (int r = 0; r < Rows; r++)
 121610    {
 121611      if (Columns <= lead) break;
 121612      int i = r;
 121613      while (Equate(b.Get(i, lead), Constant<T>.Zero))
 41614      {
 41615        i++;
 41616        if (i == Rows)
 41617        {
 41618          i = r;
 41619          lead++;
 41620          if (Columns == lead)
 41621          {
 41622            lead--;
 41623            break;
 1624          }
 01625        }
 01626      }
 961627      for (int j = 0; j < Columns; j++)
 361628      {
 361629        T temp = b.Get(r, j);
 361630        b.Set(r, j, b.Get(i, j));
 361631        b.Set(i, j, temp);
 361632      }
 121633      T div = b.Get(r, lead);
 121634      if (Inequate(div, Constant<T>.Zero))
 81635      {
 641636        for (int j = 0; j < Columns; j++)
 241637        {
 241638          b.Set(r, j, Division(b.Get(r, j), div));
 241639        }
 81640      }
 961641      for (int j = 0; j < Rows; j++)
 361642      {
 361643        if (j != r)
 241644        {
 241645          T sub = b.Get(j, lead);
 1921646          for (int k = 0; k < Columns; k++)
 721647          {
 721648            b.Set(j, k, Subtraction(b.Get(j, k), Multiplication(sub, b.Get(r, k))));
 721649          }
 241650        }
 361651      }
 121652      lead++;
 121653    }
 1654
 1655    #region Old Version
 1656
 1657    // if (a is null)
 1658    // {
 1659    //     throw new ArgumentNullException(nameof(a));
 1660    // }
 1661    // if (object.ReferenceEquals(a, b))
 1662    // {
 1663    //     a = a.Clone();
 1664    // }
 1665    // int Rows = a.Rows;
 1666    // if (b is not null && b._matrix.Length == a._matrix.Length)
 1667    // {
 1668    //     b._rows = Rows;
 1669    //     b._columns = a._columns;
 1670    //     CloneContents(a, b);
 1671    // }
 1672    // else
 1673    // {
 1674    //     b = a.Clone();
 1675    // }
 1676    // for (int i = 0; i < Rows; i++)
 1677    // {
 1678    //     if (Compute.Equal(b.Get(i, i), Constant<T>.Zero))
 1679    //     {
 1680    //         for (int j = i + 1; j < Rows; j++)
 1681    //         {
 1682    //             if (Compute.NotEqual(b.Get(j, i), Constant<T>.Zero))
 1683    //             {
 1684    //                 SwapRows(b, i, j);
 1685    //             }
 1686    //         }
 1687    //     }
 1688    //     if (Compute.Equal(b.Get(i, i), Constant<T>.Zero))
 1689    //     {
 1690    //         continue;
 1691    //     }
 1692    //     if (Compute.NotEqual(b.Get(i, i), Constant<T>.One))
 1693    //     {
 1694    //         for (int j = i + 1; j < Rows; j++)
 1695    //         {
 1696    //             if (Compute.Equal(b.Get(j, i), Constant<T>.One))
 1697    //             {
 1698    //                 SwapRows(b, i, j);
 1699    //             }
 1700    //         }
 1701    //     }
 1702    //     T rowMiltiplier = Compute.Divide(Constant<T>.One, b.Get(i, i));
 1703    //     RowMultiplication(b, i, rowMiltiplier);
 1704    //     for (int j = i + 1; j < Rows; j++)
 1705    //     {
 1706    //         T rowAddend = Compute.Negate(b.Get(j, i));
 1707    //         RowAddition(b, j, i, rowAddend);
 1708    //     }
 1709    //     for (int j = i - 1; j >= 0; j--)
 1710    //     {
 1711    //         T rowAddend = Compute.Negate(b.Get(j, i));
 1712    //         RowAddition(b, j, i, rowAddend);
 1713    //     }
 1714    // }
 1715
 1716    #endregion
 41717  }
 1718
 1719  /// <summary>Calculates the echelon of a matrix and reduces it (aka RREF).</summary>
 1720  /// <param name="a">The matrix matrix to calculate the reduced echelon of (aka RREF).</param>
 1721  /// <returns>The reduced echelon of the matrix (aka RREF).</returns>
 1722  public static Matrix<T> ReducedEchelon(Matrix<T> a)
 41723  {
 41724    Matrix<T>? b = null;
 41725    ReducedEchelon(a, ref b);
 41726    return b!;
 41727  }
 1728
 1729  /// <summary>Calculates the echelon of a matrix and reduces it (aka RREF).</summary>
 1730  /// <param name="b">The reduced echelon of the matrix (aka RREF).</param>
 1731  public void ReducedEchelon(ref Matrix<T>? b)
 01732  {
 01733    ReducedEchelon(this, ref b);
 01734  }
 1735
 1736  /// <summary>Matrixs the reduced echelon form of this matrix (aka RREF).</summary>
 1737  /// <returns>The computed reduced echelon form of this matrix (aka RREF).</returns>
 1738  public Matrix<T> ReducedEchelon()
 41739  {
 41740    return ReducedEchelon(this);
 41741  }
 1742
 1743  #endregion
 1744
 1745  #region Inverse
 1746
 1747  /// <summary>Calculates the inverse of a matrix.</summary>
 1748  /// <param name="a">The matrix to calculate the inverse of.</param>
 1749  /// <param name="b">The inverse of the matrix.</param>
 1750  public static void Inverse(Matrix<T> a, ref Matrix<T>? b)
 21751  {
 21752    if (a is null) throw new ArgumentNullException(nameof(a));
 21753    if (sourceof(!a.IsSquare, out string c1)) throw new ArgumentException(c1);
 21754    T determinant = Determinant(a);
 21755    if (Equate(determinant, Constant<T>.Zero))
 01756    {
 01757      throw new ArgumentException("Singular matrix encountered during inverse caluculation (cannot be inversed).");
 1758    }
 21759    Matrix<T> adjoint = a.Adjoint();
 21760    int dimension = a.Rows;
 21761    int Length = a.Length;
 21762    if (object.ReferenceEquals(a, b))
 01763    {
 01764      b = a.Clone();
 01765    }
 21766    else if (b is not null && b.Length == Length)
 01767    {
 01768      b._rows = dimension;
 01769      b._columns = dimension;
 01770    }
 1771    else
 21772    {
 21773      b = new Matrix<T>(dimension, dimension, Length);
 21774    }
 161775    for (int i = 0; i < dimension; i++)
 61776    {
 481777      for (int j = 0; j < dimension; j++)
 181778      {
 181779        b.Set(i, j, Division(adjoint.Get(i, j), determinant));
 181780      }
 61781    }
 1782
 1783    #region Old Version
 1784
 1785    //// Note: this method can be optimized...
 1786
 1787    // if (a is null)
 1788    // {
 1789    //     throw new ArgumentNullException(nameof(a));
 1790    // }
 1791    // if (Compute.Equal(Determinant(a), Constant<T>.Zero))
 1792    // {
 1793    //     throw new MathematicsException("inverse calculation failed.");
 1794    // }
 1795    // Matrix<T> identity = FactoryIdentity(a.Rows, a.Columns);
 1796    // Matrix<T> rref = a.Clone();
 1797    // for (int i = 0; i < a.Rows; i++)
 1798    // {
 1799    //     if (Compute.Equal(rref[i, i], Constant<T>.Zero))
 1800    //     {
 1801    //         for (int j = i + 1; j < rref.Rows; j++)
 1802    //         {
 1803    //             if (Compute.NotEqual(rref[j, i], Constant<T>.Zero))
 1804    //             {
 1805    //                 SwapRows(rref, i, j);
 1806    //                 SwapRows(identity, i, j);
 1807    //             }
 1808    //         }
 1809    //     }
 1810    //     T identityRowMultiplier = Compute.Divide(Constant<T>.One, rref[i, i]);
 1811    //     RowMultiplication(identity, i, identityRowMultiplier);
 1812    //     RowMultiplication(rref, i, identityRowMultiplier);
 1813    //     for (int j = i + 1; j < rref.Rows; j++)
 1814    //     {
 1815    //         T rowAdder = Compute.Negate(rref[j, i]);
 1816    //         RowAddition(identity, j, i, rowAdder);
 1817    //         RowAddition(rref, j, i, rowAdder);
 1818    //     }
 1819    //     for (int j = i - 1; j >= 0; j--)
 1820    //     {
 1821    //         T rowAdder = Compute.Negate(rref[j, i]);
 1822    //         RowAddition(identity, j, i, rowAdder);
 1823    //         RowAddition(rref, j, i, rowAdder);
 1824    //     }
 1825    // }
 1826    // b = identity;
 1827
 1828    #endregion
 1829
 1830    #region Alternate Version
 1831
 1832    // Matrix<T> identity = Matrix<T>.FactoryIdentity(matrix.Rows, matrix.Columns);
 1833    // Matrix<T> rref = matrix.Clone();
 1834    // for (int i = 0; i < matrix.Rows; i++)
 1835    // {
 1836    //   if (Compute.Equate(rref[i, i], Compute.FromInt32(0)))
 1837    //     for (int j = i + 1; j < rref.Rows; j++)
 1838    //       if (!Compute.Equate(rref[j, i], Compute.FromInt32(0)))
 1839    //       {
 1840    //         Matrix<T>.SwapRows(rref, i, j);
 1841    //         Matrix<T>.SwapRows(identity, i, j);
 1842    //       }
 1843    //   Matrix<T>.RowMultiplication(identity, i, Compute.Divide(Compute.FromInt32(1), rref[i, i]));
 1844    //   Matrix<T>.RowMultiplication(rref, i, Compute.Divide(Compute.FromInt32(1), rref[i, i]));
 1845    //   for (int j = i + 1; j < rref.Rows; j++)
 1846    //   {
 1847    //     Matrix<T>.RowAddition(identity, j, i, Compute.Negate(rref[j, i]));
 1848    //     Matrix<T>.RowAddition(rref, j, i, Compute.Negate(rref[j, i]));
 1849    //   }
 1850    //   for (int j = i - 1; j >= 0; j--)
 1851    //   {
 1852    //     Matrix<T>.RowAddition(identity, j, i, Compute.Negate(rref[j, i]));
 1853    //     Matrix<T>.RowAddition(rref, j, i, Compute.Negate(rref[j, i]));
 1854    //   }
 1855    // }
 1856    // return identity;
 1857
 1858    #endregion
 21859  }
 1860
 1861  /// <summary>Calculates the inverse of a matrix.</summary>
 1862  /// <param name="a">The matrix to calculate the inverse of.</param>
 1863  /// <returns>The inverse of the matrix.</returns>
 1864  public static Matrix<T> Inverse(Matrix<T> a)
 21865  {
 21866    Matrix<T>? b = null;
 21867    Inverse(a, ref b);
 21868    return b!;
 21869  }
 1870
 1871  /// <summary>Matrixs the inverse of this matrix.</summary>
 1872  /// <returns>The inverse of this matrix.</returns>
 1873  public Matrix<T> Inverse()
 21874  {
 21875    return Inverse(this);
 21876  }
 1877
 1878  #endregion
 1879
 1880  #region Adjoint
 1881
 1882  /// <summary>Calculates the adjoint of a matrix.</summary>
 1883  /// <param name="a">The matrix to calculate the adjoint of.</param>
 1884  /// <param name="b">The adjoint of the matrix.</param>
 1885  public static void Adjoint(Matrix<T> a, ref Matrix<T>? b)
 61886  {
 61887    if (a is null) throw new ArgumentNullException(nameof(a));
 61888    if (sourceof(!a.IsSquare, out string c1)) throw new ArgumentException(c1);
 61889    int dimension = a.Rows;
 61890    int Length = a.Length;
 61891    if (ReferenceEquals(a, b))
 01892    {
 01893      b = a.Clone();
 01894    }
 61895    else if (b is not null && b.Length == Length)
 01896    {
 01897      b._rows = dimension;
 01898      b._columns = dimension;
 01899    }
 1900    else
 61901    {
 61902      b = new Matrix<T>(dimension, dimension, Length);
 61903    }
 61904    if (dimension is 1)
 01905    {
 01906      b.Set(0, 0, Constant<T>.One);
 01907      return;
 1908    }
 61909    Matrix<T> temp = new(dimension, dimension, Length);
 481910    for (int i = 0; i < dimension; i++)
 181911    {
 1441912      for (int j = 0; j < dimension; j++)
 541913      {
 541914        GetCofactor(a, temp, i, j, dimension);
 541915        T sign = (i + j) % 2 is 0 ? Constant<T>.One : Constant<T>.NegativeOne;
 541916        b.Set(j, i, Multiplication(sign, GetDeterminantGaussian(temp, dimension - 1)));
 541917      }
 181918    }
 1919
 1920    #region Old Version
 1921
 1922    // if (a is null)
 1923    // {
 1924    //     throw new ArgumentNullException(nameof(a));
 1925    // }
 1926    // if (!a.IsSquare)
 1927    // {
 1928    //     throw new MathematicsException("Argument invalid !(" + nameof(a) + "." + nameof(a.IsSquare) + ")");
 1929    // }
 1930    // if (object.ReferenceEquals(a, b))
 1931    // {
 1932    //     a = a.Clone();
 1933    // }
 1934    // int Length = a.Length;
 1935    // int Rows = a.Rows;
 1936    // int Columns = a.Columns;
 1937    // if (b is not null && b.Length == Length)
 1938    // {
 1939    //     b._rows = Rows;
 1940    //     b._columns = Columns;
 1941    // }
 1942    // else
 1943    // {
 1944    //     b = new Matrix<T>(Rows, Columns, Length);
 1945    // }
 1946    // for (int i = 0; i < Rows; i++)
 1947    // {
 1948    //     for (int j = 0; j < Columns; j++)
 1949    //     {
 1950    //         if (Compute.IsEven(a.Get(i, j)))
 1951    //         {
 1952    //             b[i, j] = Determinant(Minor(a, i, j));
 1953    //         }
 1954    //         else
 1955    //         {
 1956    //             b[i, j] = Compute.Negate(Determinant(Minor(a, i, j)));
 1957    //         }
 1958    //     }
 1959    // }
 1960
 1961    #endregion
 61962  }
 1963
 1964  /// <summary>Calculates the adjoint of a matrix.</summary>
 1965  /// <param name="a">The matrix to calculate the adjoint of.</param>
 1966  /// <returns>The adjoint of the matrix.</returns>
 1967  public static Matrix<T> Adjoint(Matrix<T> a)
 61968  {
 61969    Matrix<T>? b = null;
 61970    Adjoint(a, ref b);
 61971    return b!;
 61972  }
 1973
 1974  /// <summary>Calculates the adjoint of a matrix.</summary>
 1975  /// <param name="b">The adjoint of the matrix.</param>
 1976  public void Adjoint(ref Matrix<T>? b)
 01977  {
 01978    Adjoint(this, ref b);
 01979  }
 1980
 1981  /// <summary>Calculates the adjoint of a matrix.</summary>
 1982  /// <returns>The adjoint of the matrix.</returns>
 1983  public Matrix<T> Adjoint()
 61984  {
 61985    return Adjoint(this);
 61986  }
 1987
 1988  #endregion
 1989
 1990  #region Transpose
 1991
 1992  /// <summary>Returns the transpose of a matrix.</summary>
 1993  /// <param name="a">The matrix to transpose.</param>
 1994  /// <param name="b">The transpose of the matrix.</param>
 1995  public static void Transpose(Matrix<T> a, ref Matrix<T>? b)
 31996  {
 31997    if (a is null) throw new ArgumentNullException(nameof(a));
 31998    if (ReferenceEquals(a, b))
 01999    {
 02000      if (b.IsSquare)
 02001      {
 02002        TransposeContents(b);
 02003        return;
 2004      }
 02005    }
 32006    int Length = a.Length;
 32007    int Rows = a.Columns;
 32008    int Columns = a.Rows;
 32009    if (b is not null && b.Length == a.Length && !ReferenceEquals(a, b))
 02010    {
 02011      b._rows = Rows;
 02012      b._columns = Columns;
 02013    }
 2014    else
 32015    {
 32016      b = new Matrix<T>(Rows, Columns, Length);
 32017    }
 182018    for (int i = 0; i < Rows; i++)
 62019    {
 342020      for (int j = 0; j < Columns; j++)
 112021      {
 112022        b.Set(i, j, a.Get(j, i));
 112023      }
 62024    }
 32025  }
 2026
 2027  /// <summary>Returns the transpose of a matrix.</summary>
 2028  /// <param name="a">The matrix to transpose.</param>
 2029  /// <returns>The transpose of the matrix.</returns>
 2030  public static Matrix<T> Transpose(Matrix<T> a)
 32031  {
 32032    Matrix<T>? b = null;
 32033    Transpose(a, ref b);
 32034    return b!;
 32035  }
 2036
 2037  /// <summary>Returns the transpose of a matrix.</summary>
 2038  /// <param name="b">The transpose of the matrix.</param>
 2039  public void Transpose(ref Matrix<T>? b)
 02040  {
 02041    Transpose(this, ref b);
 02042  }
 2043
 2044  /// <summary>Returns the transpose of a matrix.</summary>
 2045  /// <returns>The transpose of the matrix.</returns>
 2046  public Matrix<T> Transpose()
 32047  {
 32048    return Transpose(this);
 32049  }
 2050
 2051  #endregion
 2052
 2053  #region DecomposeLowerUpper
 2054
 2055  /// <summary>Decomposes a matrix into lower-upper reptresentation.</summary>
 2056  /// <param name="matrix">The matrix to decompose.</param>
 2057  /// <param name="lower">The computed lower triangular matrix.</param>
 2058  /// <param name="upper">The computed upper triangular matrix.</param>
 2059  public static void DecomposeLowerUpper(Matrix<T> matrix, ref Matrix<T> lower, ref Matrix<T> upper)
 02060  {
 2061    // Note: this method can be optimized...
 2062
 02063    lower = Matrix<T>.FactoryIdentity(matrix.Rows, matrix.Columns);
 02064    upper = matrix.Clone();
 02065    int[] permutation = new int[matrix.Rows];
 02066    for (int i = 0; i < matrix.Rows; i++)
 02067    {
 02068      permutation[i] = i;
 02069    }
 02070    T pom2, detOfP = Constant<T>.One;
 02071    int k0 = 0;
 02072    for (int k = 0; k < matrix.Columns - 1; k++)
 02073    {
 02074      T p = Constant<T>.Zero;
 02075      for (int i = k; i < matrix.Rows; i++)
 02076      {
 02077        if (GreaterThan(GreaterThan(upper[i, k], Constant<T>.Zero) ? upper[i, k] : Negation(upper[i, k]), p))
 02078        {
 02079          p = GreaterThan(upper[i, k], Constant<T>.Zero) ? upper[i, k] : Negation(upper[i, k]);
 02080          k0 = i;
 02081        }
 02082      }
 02083      if (Equate(p, Constant<T>.Zero))
 02084      {
 02085        throw new ArgumentException("The matrix is singular!");
 2086      }
 02087      (permutation[k0], permutation[k]) = (permutation[k], permutation[k0]);
 02088      for (int i = 0; i < k; i++)
 02089      {
 02090        pom2 = lower[k, i];
 02091        lower[k, i] = lower[k0, i];
 02092        lower[k0, i] = pom2;
 02093      }
 02094      if (k != k0)
 02095      {
 02096        detOfP = Multiplication(detOfP, Constant<T>.NegativeOne);
 02097      }
 02098      for (int i = 0; i < matrix.Columns; i++)
 02099      {
 02100        pom2 = upper[k, i];
 02101        upper[k, i] = upper[k0, i];
 02102        upper[k0, i] = pom2;
 02103      }
 02104      for (int i = k + 1; i < matrix.Rows; i++)
 02105      {
 02106        lower[i, k] = Division(upper[i, k], upper[k, k]);
 02107        for (int j = k; j < matrix.Columns; j++)
 02108        {
 02109          upper[i, j] = Subtraction(upper[i, j], Multiplication(lower[i, k], upper[k, j]));
 02110        }
 02111      }
 02112    }
 2113
 2114    #region Alternate Version
 2115
 2116    // lower = Matrix<T>.FactoryIdentity(matrix.Rows, matrix.Columns);
 2117    // upper = matrix.Clone();
 2118    // int[] permutation = new int[matrix.Rows];
 2119    // for (int i = 0; i < matrix.Rows; i++) permutation[i] = i;
 2120    // T p = 0, pom2, detOfP = 1;
 2121    // int k0 = 0, pom1 = 0;
 2122    // for (int k = 0; k < matrix.Columns - 1; k++)
 2123    // {
 2124    //     p = 0;
 2125    //     for (int i = k; i < matrix.Rows; i++)
 2126    //         if ((upper[i, k] > 0 ? upper[i, k] : -upper[i, k]) > p)
 2127    //         {
 2128    //             p = upper[i, k] > 0 ? upper[i, k] : -upper[i, k];
 2129    //             k0 = i;
 2130    //         }
 2131    //     if (p is 0)
 2132    //         throw new System.Exception("The matrix is singular!");
 2133    //     pom1 = permutation[k];
 2134    //     permutation[k] = permutation[k0];
 2135    //     permutation[k0] = pom1;
 2136    //     for (int i = 0; i < k; i++)
 2137    //     {
 2138    // pom2 = lower[k, i];
 2139    //         lower[k, i] = lower[k0, i];
 2140    //         lower[k0, i] = pom2;
 2141    //     }
 2142    //     if (k != k0)
 2143    //         detOfP *= -1;
 2144    //     for (int i = 0; i < matrix.Columns; i++)
 2145    //     {
 2146    //         pom2 = upper[k, i];
 2147    //         upper[k, i] = upper[k0, i];
 2148    //         upper[k0, i] = pom2;
 2149    //     }
 2150    //     for (int i = k + 1; i < matrix.Rows; i++)
 2151    //     {
 2152    //         lower[i, k] = upper[i, k] / upper[k, k];
 2153    //         for (int j = k; j < matrix.Columns; j++)
 2154    //             upper[i, j] = upper[i, j] - lower[i, k] * upper[k, j];
 2155    //     }
 2156    // }
 2157
 2158    #endregion
 02159  }
 2160
 2161  /// <summary>Decomposes a matrix into lower-upper reptresentation.</summary>
 2162  /// <param name="lower">The computed lower triangular matrix.</param>
 2163  /// <param name="upper">The computed upper triangular matrix.</param>
 2164  public void DecomposeLowerUpper(ref Matrix<T> lower, ref Matrix<T> upper)
 02165  {
 02166    DecomposeLowerUpper(this, ref lower, ref upper);
 02167  }
 2168
 2169  #endregion
 2170
 2171  #region Rotate
 2172
 2173  /// <summary>Rotates a 4x4 matrix around an 3D axis by a specified angle.</summary>
 2174  /// <param name="matrix">The 4x4 matrix to rotate.</param>
 2175  /// <param name="angle">The angle of rotation around the axis.</param>
 2176  /// <param name="axis">The 3D axis to rotate the matrix around.</param>
 2177  /// <returns>The rotated matrix.</returns>
 2178  public static Matrix<T> Rotate4x4(Matrix<T> matrix, Angle<T> angle, Vector<T> axis)
 02179  {
 02180    if (axis is null) throw new ArgumentNullException(nameof(axis));
 02181    if (matrix is null) throw new ArgumentNullException(nameof(matrix));
 02182    if (sourceof(axis._vector.Length is not 3, out string c1)) throw new ArgumentException(c1);
 02183    if (sourceof(matrix._rows is not 4 || matrix._columns is not 4, out string c2)) throw new ArgumentException(c2);
 2184
 2185    // if the angle is zero, no rotation is required
 02186    if (Equate(angle._measurement, Constant<T>.Zero))
 02187    {
 02188      return matrix.Clone();
 2189    }
 2190
 02191    T cosine = CosineSystem(angle);
 02192    T sine = SineSystem(angle);
 02193    T oneMinusCosine = Subtraction(Constant<T>.One, cosine);
 02194    T xy = Multiplication(axis.X, axis.Y);
 02195    T yz = Multiplication(axis.Y, axis.Z);
 02196    T xz = Multiplication(axis.X, axis.Z);
 02197    T xs = Multiplication(axis.X, sine);
 02198    T ys = Multiplication(axis.Y, sine);
 02199    T zs = Multiplication(axis.Z, sine);
 2200
 02201    T f00 = Addition(Multiplication(Multiplication(axis.X, axis.X), oneMinusCosine), cosine);
 02202    T f01 = Addition(Multiplication(xy, oneMinusCosine), zs);
 02203    T f02 = Subtraction(Multiplication(xz, oneMinusCosine), ys);
 2204    // n[3] not used
 02205    T f10 = Subtraction(Multiplication(xy, oneMinusCosine), zs);
 02206    T f11 = Addition(Multiplication(Multiplication(axis.Y, axis.Y), oneMinusCosine), cosine);
 02207    T f12 = Addition(Multiplication(yz, oneMinusCosine), xs);
 2208    // n[7] not used
 02209    T f20 = Addition(Multiplication(xz, oneMinusCosine), ys);
 02210    T f21 = Subtraction(Multiplication(yz, oneMinusCosine), xs);
 02211    T f22 = Addition(Multiplication(Multiplication(axis.Z, axis.Z), oneMinusCosine), cosine);
 2212
 2213    // Row 1
 02214    T _0_0 = Addition(Addition(Multiplication(matrix[0, 0], f00), Multiplication(matrix[1, 0], f01)), Multiplication(mat
 02215    T _0_1 = Addition(Addition(Multiplication(matrix[0, 1], f00), Multiplication(matrix[1, 1], f01)), Multiplication(mat
 02216    T _0_2 = Addition(Addition(Multiplication(matrix[0, 2], f00), Multiplication(matrix[1, 2], f01)), Multiplication(mat
 02217    T _0_3 = Addition(Addition(Multiplication(matrix[0, 3], f00), Multiplication(matrix[1, 3], f01)), Multiplication(mat
 2218    // Row 2
 02219    T _1_0 = Addition(Addition(Multiplication(matrix[0, 0], f10), Multiplication(matrix[1, 0], f11)), Multiplication(mat
 02220    T _1_1 = Addition(Addition(Multiplication(matrix[0, 1], f10), Multiplication(matrix[1, 1], f11)), Multiplication(mat
 02221    T _1_2 = Addition(Addition(Multiplication(matrix[0, 2], f10), Multiplication(matrix[1, 2], f11)), Multiplication(mat
 02222    T _1_3 = Addition(Addition(Multiplication(matrix[0, 3], f10), Multiplication(matrix[1, 3], f11)), Multiplication(mat
 2223    // Row 3
 02224    T _2_0 = Addition(Addition(Multiplication(matrix[0, 0], f20), Multiplication(matrix[1, 0], f21)), Multiplication(mat
 02225    T _2_1 = Addition(Addition(Multiplication(matrix[0, 1], f20), Multiplication(matrix[1, 1], f21)), Multiplication(mat
 02226    T _2_2 = Addition(Addition(Multiplication(matrix[0, 2], f20), Multiplication(matrix[1, 2], f21)), Multiplication(mat
 02227    T _2_3 = Addition(Addition(Multiplication(matrix[0, 3], f20), Multiplication(matrix[1, 3], f21)), Multiplication(mat
 2228    // Row 4
 02229    T _3_0 = Constant<T>.Zero;
 02230    T _3_1 = Constant<T>.Zero;
 02231    T _3_2 = Constant<T>.Zero;
 02232    T _3_3 = Constant<T>.One;
 2233
 2234#pragma warning disable CS8509 // The switch expression does not handle all possible values of its input type (it is not
 02235    return new Matrix<T>(4, 4, (row, column) =>
 02236      (row, column) switch
 02237      {
 02238        /* 0 */ (0, 0) => _0_0, (0, 1) => _0_1, (0, 2) => _0_2, (0, 3) => _0_3,
 02239        /* 1 */ (1, 0) => _1_0, (1, 1) => _1_1, (1, 2) => _1_2, (1, 3) => _1_3,
 02240        /* 2 */ (2, 0) => _2_0, (2, 1) => _2_1, (2, 2) => _2_2, (2, 3) => _2_3,
 02241        /* 3 */ (3, 0) => _3_0, (3, 1) => _3_1, (3, 2) => _3_2, (3, 3) => _3_3,
 02242      });
 2243#pragma warning restore CS8509 // The switch expression does not handle all possible values of its input type (it is not
 02244  }
 2245
 2246  /// <summary>Converts an angle around an axis into a 4x4 rotational matrix.</summary>
 2247  /// <param name="angle">The angle of the axis rotation.</param>
 2248  /// <param name="axis">The axis of the axis rotation.</param>
 2249  /// <returns>The rotation expressed as a 4x4 matrix.</returns>
 02250  public Matrix<T> Rotate4x4(Angle<T> angle, Vector<T> axis) => Rotate4x4(this, angle, axis);
 2251
 2252  #endregion
 2253
 2254  #region Equal
 2255
 2256  /// <summary>Does a value equality check.</summary>
 2257  /// <param name="a">The first matrix to check for equality.</param>
 2258  /// <param name="b">The second matrix to check for equality.</param>
 2259  /// <returns>True if values are equal, false if not.</returns>
 2260  public static bool Equal(Matrix<T> a, Matrix<T> b)
 672261  {
 672262    if (a is null)
 02263    {
 02264      if (b is null)
 02265      {
 02266        return true;
 2267      }
 2268      else
 02269      {
 02270        return false;
 2271      }
 2272    }
 672273    if (b is null)
 02274    {
 02275      return false;
 2276    }
 672277    int Rows = a.Rows;
 672278    int Columns = a.Columns;
 672279    if (Rows != b.Rows || Columns != b.Columns)
 02280    {
 02281      return false;
 2282    }
 672283    T[] A = a._matrix;
 672284    T[] B = b._matrix;
 672285    int Length = A.Length;
 10742286    for (int i = 0; i < Length; i++)
 4702287    {
 4702288      if (!Equate(A[i], B[i]))
 02289      {
 02290        return false;
 2291      }
 4702292    }
 672293    return true;
 672294  }
 2295
 2296  /// <summary>Does a value equality check.</summary>
 2297  /// <param name="a">The first matrix to check for equality.</param>
 2298  /// <param name="b">The second matrix to check for equality.</param>
 2299  /// <returns>True if values are equal, false if not.</returns>
 2300  public static bool operator ==(Matrix<T> a, Matrix<T> b)
 672301  {
 672302    return Equal(a, b);
 672303  }
 2304
 2305  /// <summary>Does a value non-equality check.</summary>
 2306  /// <param name="a">The first matrix to check for non-equality.</param>
 2307  /// <param name="b">The second matrix to check for non-equality.</param>
 2308  /// <returns>True if values are not equal, false if not.</returns>
 2309  public static bool operator !=(Matrix<T> a, Matrix<T> b)
 02310  {
 02311    return !Equal(a, b);
 02312  }
 2313
 2314  /// <summary>Does a value equality check.</summary>
 2315  /// <param name="b">The second matrix to check for equality.</param>
 2316  /// <returns>True if values are equal, false if not.</returns>
 2317  public bool Equal(Matrix<T> b)
 02318  {
 02319    return this == b;
 02320  }
 2321
 2322  #endregion
 2323
 2324  #region Equal (+leniency)
 2325
 2326  /// <summary>Does a value equality check with leniency.</summary>
 2327  /// <param name="a">The first matrix to check for equality.</param>
 2328  /// <param name="b">The second matrix to check for equality.</param>
 2329  /// <param name="leniency">How much the values can vary but still be considered equal.</param>
 2330  /// <returns>True if values are equal, false if not.</returns>
 2331  public static bool Equal(Matrix<T> a, Matrix<T> b, T leniency)
 102332  {
 102333    if (a is null)
 02334    {
 02335      if (b is null)
 02336      {
 02337        return true;
 2338      }
 2339      else
 02340      {
 02341        return false;
 2342      }
 2343    }
 102344    if (b is null)
 02345    {
 02346      return false;
 2347    }
 102348    int Rows = a.Rows;
 102349    int Columns = a.Columns;
 102350    if (Rows != b.Rows || Columns != b.Columns)
 02351    {
 02352      return false;
 2353    }
 102354    T[] A = a._matrix;
 102355    T[] B = b._matrix;
 102356    int Length = A.Length;
 1282357    for (int i = 0; i < Length; i++)
 582358    {
 582359      if (!EqualToLeniency(A[i], B[i], leniency))
 42360      {
 42361        return false;
 2362      }
 542363    }
 62364    return true;
 102365  }
 2366
 2367  /// <summary>Does a value equality check with leniency.</summary>
 2368  /// <param name="b">The second matrix to check for equality.</param>
 2369  /// <param name="leniency">How much the values can vary but still be considered equal.</param>
 2370  /// <returns>True if values are equal, false if not.</returns>
 2371  public bool Equal(Matrix<T> b, T leniency)
 102372  {
 102373    return Equal(this, b, leniency);
 102374  }
 2375
 2376  #endregion
 2377
 2378  #endregion
 2379
 2380  #region Other Methods
 2381
 2382  #region Get/Set
 2383
 2384  internal T Get(int row, int column)
 20092385  {
 20092386    return _matrix[row * Columns + column];
 20092387  }
 2388
 2389  internal void Set(int row, int column, T value)
 9122390  {
 9122391    _matrix[row * Columns + column] = value;
 9122392  }
 2393
 2394  #endregion
 2395
 2396  #region Format
 2397
 2398  /// <summary>Fills a matrix with values using a delegate.</summary>
 2399  /// <param name="matrix">The matrix to fill the values of.</param>
 2400  /// <param name="function">The function to set the values at the relative indeces.</param>
 2401  public static void Format(Matrix<T> matrix, Func<int, int, T> function)
 2372402  {
 2372403    int Rows = matrix.Rows;
 2372404    int Columns = matrix.Columns;
 2372405    T[] MATRIX = matrix._matrix;
 2372406    int i = 0;
 17642407    for (int row = 0; row < Rows; row++)
 6452408    {
 49942409      for (int column = 0; column < Columns; column++)
 18522410      {
 18522411        MATRIX[i++] = function(row, column);
 18522412      }
 6452413    }
 2372414  }
 2415
 2416  /// <summary>Fills a matrix with values using a delegate.</summary>
 2417  /// <param name="matrix">The matrix to fill the values of.</param>
 2418  /// <param name="func">The function to set the values at the relative indeces.</param>
 2419  public static void Format(Matrix<T> matrix, Func<int, T> func)
 02420  {
 02421    matrix._matrix.Format(func);
 02422  }
 2423
 2424  #endregion
 2425
 2426  #region CloneContents
 2427
 2428  internal static void CloneContents(Matrix<T> a, Matrix<T> b)
 02429  {
 02430    T[] a_flat = a._matrix;
 02431    T[] b_flat = b._matrix;
 02432    int length = a_flat.Length;
 02433    for (int i = 0; i < length; i++)
 02434    {
 02435      b_flat[i] = a_flat[i];
 02436    }
 02437  }
 2438
 2439  #endregion
 2440
 2441  #region TransposeContents
 2442
 2443  internal static void TransposeContents(Matrix<T> a)
 02444  {
 02445    int Rows = a.Rows;
 02446    for (int i = 0; i < Rows; i++)
 02447    {
 02448      int Rows_Minus_i = Rows - i;
 02449      for (int j = 0; j < Rows_Minus_i; j++)
 02450      {
 02451        T temp = a.Get(i, j);
 02452        a.Set(i, j, a.Get(j, i));
 02453        a.Set(j, i, temp);
 02454      }
 02455    }
 02456  }
 2457
 2458  #endregion
 2459
 2460  #region Clone
 2461
 2462  /// <summary>Creates a copy of a matrix.</summary>
 2463  /// <param name="a">The matrix to copy.</param>
 2464  /// <returns>The copy of this matrix.</returns>
 2465  public static Matrix<T> Clone(Matrix<T> a)
 162466  {
 162467    if (a is null) throw new ArgumentNullException(nameof(a));
 162468    return new Matrix<T>(a);
 162469  }
 2470
 2471  /// <summary>Copies this matrix.</summary>
 2472  /// <returns>The copy of this matrix.</returns>
 2473  public Matrix<T> Clone()
 162474  {
 162475    return Clone(this);
 162476  }
 2477
 2478  #endregion
 2479
 2480  #endregion
 2481
 2482  #region Casting Operators
 2483
 2484  /// <summary>Converts a T[,] into a matrix.</summary>
 2485  /// <param name="array">The T[,] to convert to a matrix.</param>
 2486  /// <returns>The resulting matrix after conversion.</returns>
 2487  public static implicit operator Matrix<T>(T[,] array) =>
 14692488    new(array.GetLength(0), array.GetLength(1), (i, j) => array[i, j]);
 2489
 2490  /// <summary>Converts a matrix into a T[,].</summary>
 2491  /// <param name="matrix">The matrix toconvert to a T[,].</param>
 2492  /// <returns>The resulting T[,] after conversion.</returns>
 2493  public static explicit operator T[,](Matrix<T> matrix)
 02494  {
 02495    int rows = matrix._rows;
 02496    int columns = matrix._columns;
 02497    T[,] array = new T[rows, columns];
 02498    T[] MATRIX = matrix._matrix;
 02499    int k = 0;
 02500    for (int i = 0; i < rows; i++)
 02501    {
 02502      for (int j = 0; j < columns; j++)
 02503      {
 02504        array[i, j] = MATRIX[k++];
 02505      }
 02506    }
 02507    return array;
 02508  }
 2509
 2510  #endregion
 2511
 2512  #region Overrides
 2513
 2514  /// <summary>Matrixs a hash code from the values of this matrix.</summary>
 2515  /// <returns>A hash code for the matrix.</returns>
 2516  public override int GetHashCode()
 02517  {
 02518    int hashCode = HashCode.Combine(_rows, _columns);
 02519    foreach (T value in _matrix)
 02520    {
 02521      hashCode = HashCode.Combine(hashCode, Hash(value));
 02522    }
 02523    return hashCode;
 02524  }
 2525
 2526  /// <summary>Does an equality check by value.</summary>
 2527  /// <param name="b">The object to compare to.</param>
 2528  /// <returns>True if the references are equal, false if not.</returns>
 02529  public override bool Equals(object? b) => b is Matrix<T> B && Equal(this, B);
 2530
 2531  #endregion
 2532}

Methods/Properties

get_Length()
get_Rows()
get_Columns()
get_IsSquare()
get_IsVector()
get_Is2x1()
get_Is3x1()
get_Is4x1()
get_Is2x2()
get_Is3x3()
get_Is4x4()
get_Item(...)
set_Item(...)
get_Item(...)
set_Item(...)
get_DebuggerString()
.ctor(...)
.ctor(...)
.ctor(...)
.ctor(...)
.ctor(...)
.ctor(...)
.ctor(...)
FactoryZero(...)
.cctor()
FactoryIdentity(...)
FactoryUniform(...)
RowMultiplication(...)
RowAddition(...)
SwapRows(...)
SwapRows(...)
GetCofactor(...)
.ctor(...)
.ctor(...)
get_Value()
op_Addition(...)
op_Multiply(...)
op_UnaryNegation(...)
op_Subtraction(...)
op_Division(...)
op_LessThan(...)
op_Equality(...)
op_Inequality(...)
op_GreaterThan(...)
op_GreaterThanOrEqual(...)
op_LessThanOrEqual(...)
op_Explicit(...)
Abs()
get_IsDividedByZero()
GetDeterminantGaussian(...)
GetDeterminantLaplace(...)
GetIsSymetric(...)
get_IsSymetric()
Negate(...)
Negate(...)
op_UnaryNegation(...)
Negate(...)
Negate()
Add(...)
Add(...)
op_Addition(...)
Add(...)
Add(...)
Subtract(...)
Subtract(...)
op_Subtraction(...)
Subtract(...)
Subtract(...)
Multiply(...)
Multiply(...)
op_Multiply(...)
Multiply(...)
Multiply(...)
Multiply(...)
Multiply(...)
op_Multiply(...)
Multiply(...)
Multiply(...)
Multiply(...)
Multiply(...)
Multiply(...)
op_Multiply(...)
op_Multiply(...)
Multiply(...)
Multiply(...)
Divide(...)
Divide(...)
op_Division(...)
Divide(...)
Divide(...)
Power(...)
Power(...)
op_ExclusiveOr(...)
Power(...)
Power(...)
Determinant(...)
DeterminantGaussian(...)
DeterminantLaplace(...)
Determinant()
DeterminantLaplace()
DeterminantGaussian()
Trace(...)
Trace()
XML_Minor()
Minor(...)
Minor(...)
Minor(...)
Minor(...)
ConcatenateRowWise(...)
ConcatenateRowWise(...)
ConcatenateRowWise(...)
ConcatenateRowWise(...)
ReducedEchelon(...)
ReducedEchelon(...)
ReducedEchelon(...)
ReducedEchelon()
Inverse(...)
Inverse(...)
Inverse()
Adjoint(...)
Adjoint(...)
Adjoint(...)
Adjoint()
Transpose(...)
Transpose(...)
Transpose(...)
Transpose()
DecomposeLowerUpper(...)
DecomposeLowerUpper(...)
Rotate4x4(...)
Rotate4x4(...)
Equal(...)
op_Equality(...)
op_Inequality(...)
Equal(...)
Equal(...)
Equal(...)
Get(...)
Set(...)
Format(...)
Format(...)
CloneContents(...)
TransposeContents(...)
Clone(...)
Clone()
op_Implicit(...)
op_Explicit(...)
GetHashCode()
Equals(...)