public static double[] Power(double[] aStore, int dimension, int power) { // We take powers via the exponentiation-by-squaring algorithm. // This is not strictly optimal, but it is very simple, is optimal in most cases (e.g. all n<15), // and is nearly optimal (e.g. 6 multiplies instead of 5 for n=15) even when it is not perfectly optimal. if (power == 1) { return(aStore); // Returning the given storage for A^1 instead of copying it saves space and time and works fine when this point is reached via recursion, // since that storage will just be read for a multiply, not returned to the calling user. But it would be bad to do so when the user requests // A^1, since the returned matrix would not be independent of the original. So don't call this method to compute A^1 for the user. } else { if (power % 2 == 0) { // return (A * A)^{n/2} double[] bStore = MatrixAlgorithms.Multiply(aStore, dimension, dimension, aStore, dimension, dimension); double[] cStore = Power(bStore, dimension, power / 2); return(cStore); } else { // return A * (A * A)^{(n-1)/2} double[] bStore = MatrixAlgorithms.Multiply(aStore, dimension, dimension, aStore, dimension, dimension); double[] cStore = Power(bStore, dimension, (power - 1) / 2); double[] dStore = MatrixAlgorithms.Multiply(aStore, dimension, dimension, cStore, dimension, dimension); return(dStore); } } }
/// <summary> /// Negates a real, rectangular matrix. /// </summary> /// <param name="A">The matrix.</param> /// <returns>The matrix -A.</returns> public static RectangularMatrix operator -(RectangularMatrix A) { if (A == null) { throw new ArgumentNullException(nameof(A)); } double[] store = MatrixAlgorithms.Multiply(-1.0, A.store, A.offset, A.rowStride, A.colStride, A.rows, A.cols); return(new RectangularMatrix(store, A.rows, A.cols)); }
/// <summary> /// Divides a real, rectangular matrix by a real constant. /// </summary> /// <param name="A">The matrix.</param> /// <param name="alpha">The constant.</param> /// <returns>The quotient A/a.</returns> public static RectangularMatrix operator *(RectangularMatrix A, double alpha) { if (A == null) { throw new ArgumentNullException("A"); } double[] store = MatrixAlgorithms.Multiply(1.0 / alpha, A.store, A.rows, A.cols); return(new RectangularMatrix(store, A.rows, A.cols)); }
/// <summary> /// Negates a real, square matrix. /// </summary> /// <param name="A">The matrix.</param> /// <returns>The matrix -A.</returns> /// <exception cref="ArgumentNullException"><paramref name="A"/> is <see langword="null"/>.</exception> public static SquareMatrix operator -(SquareMatrix A) { if (A == null) { throw new ArgumentNullException(nameof(A)); } double[] store = MatrixAlgorithms.Multiply(-1.0, A.store, A.offset, A.rowStride, A.colStride, A.dimension, A.dimension); return(new SquareMatrix(store, A.dimension)); }
/// <summary> /// Divides a real, square matrix by a real constant. /// </summary> /// <param name="A">The matrix.</param> /// <param name="alpha">The constant.</param> /// <returns>The quotient A/a.</returns> public static SquareMatrix operator *(SquareMatrix A, double alpha) { if (A == null) { throw new ArgumentNullException("A"); } double[] store = MatrixAlgorithms.Multiply(1.0 / alpha, A.store, A.dimension, A.dimension); return(new SquareMatrix(store, A.dimension)); }
/// <summary> /// Multiplies two real, rectangular matrices. /// </summary> /// <param name="A">The first matrix.</param> /// <param name="B">The second matrix.</param> /// <returns>The product matrix AB.</returns> public static RectangularMatrix operator *(RectangularMatrix A, RectangularMatrix B) { // this is faster than the base operator, because it knows about the underlying structure if (A == null) { throw new ArgumentNullException("A"); } if (B == null) { throw new ArgumentNullException("B"); } if (A.cols != B.rows) { throw new DimensionMismatchException(); } double[] abStore = MatrixAlgorithms.Multiply(A.store, A.rows, A.cols, B.store, B.rows, B.cols); return(new RectangularMatrix(abStore, A.rows, B.cols)); }
/// <summary> /// Computes the product of two square matrices. /// </summary> /// <param name="A">The first matrix.</param> /// <param name="B">The second matrix.</param> /// <returns>The product <paramref name="A"/> * <paramref name="B"/>.</returns> /// <remarks> /// <para>Note that matrix multiplication is not commutative, i.e. M1*M2 is generally not the same as M2*M1.</para> /// <para>Matrix multiplication is an O(N<sup>3</sup>) process.</para> /// </remarks> /// <exception cref="ArgumentNullException"><paramref name="A"/> or <paramref name="B"/> is null.</exception> /// <exception cref="DimensionMismatchException">The dimension of <paramref name="A"/> is not the same as the dimension of <paramref name="B"/>.</exception> public static SquareMatrix operator *(SquareMatrix A, SquareMatrix B) { // this is faster than the base operator, because it knows about the underlying structure if (A == null) { throw new ArgumentNullException("A"); } if (B == null) { throw new ArgumentNullException("B"); } if (A.dimension != B.dimension) { throw new DimensionMismatchException(); } double[] abStore = MatrixAlgorithms.Multiply(A.store, A.dimension, A.dimension, B.store, B.dimension, B.dimension); return(new SquareMatrix(abStore, A.dimension)); }
/// <summary> /// Solve the system of equations Ax=b, where A is the original matrix. /// </summary> /// <param name="rhs">The right-hand-side vector b.</param> /// <returns>The solution vector x.</returns> /// <remarks> /// <para>The components of <paramref name="rhs"/> are not modified.</para> /// </remarks> public ColumnVector Solve(IList <double> rhs) { if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } if (rhs.Count != dimension) { throw new DimensionMismatchException(); } double[] y = new double[rhs.Count]; rhs.CopyTo(y, 0); y = MatrixAlgorithms.Multiply(qtStore, dimension, dimension, y, dimension, 1); SquareMatrixAlgorithms.SolveUpperRightTriangular(rStore, y, 0, dimension); return(new ColumnVector(y, dimension)); }