/// <summary> /// Solves A x = b. /// </summary> /// <param name="rhs">The right-hand side vector b.</param> /// <returns>The solution vector x.</returns> /// <exception cref="ArgumentNullException"><paramref name="rhs"/> is <c>null</c>.</exception> /// <exception cref="DimensionMismatchException">The dimension of <paramref name="rhs"/> is not the same as the dimension of the matrix.</exception> public ColumnVector Solve(IReadOnlyList <double> rhs) { if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } if (rhs.Count != dimension) { throw new DimensionMismatchException(); } // copy rhs into an array, reshuffling according to permutations double[] x = new double[dimension]; for (int i = 0; i < x.Length; i++) { x[i] = rhs[permutation[i]]; } // solve Ly=b and Ux=y Blas2.dTrsv(false, true, luStore, 0, 1, dimension, x, 0, 1, dimension); //SquareMatrixAlgorithms.SolveLowerLeftTriangular(luStore, x, 0, dimension); Blas2.dTrsv(true, false, luStore, 0, 1, dimension, x, 0, 1, dimension); //SquareMatrixAlgorithms.SolveUpperRightTriangular(luStore, x, 0, dimension); return(new ColumnVector(x, dimension)); }
/// <summary> /// Solve the system A x = b. /// </summary> /// <param name="rhs">The right-hand-side b.</param> /// <returns>The column vector x for which A x is closest to b.</returns> public ColumnVector Solve(IReadOnlyList <double> rhs) { if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } if (rhs.Count != rows) { throw new DimensionMismatchException(); } // BLAS requires an array, but doesn't modify it, so if given one, use it directly double[] x = rhs as double[]; if (x == null) { x = new double[rows]; rhs.CopyTo(x, 0); } // Q^T x is a row-length vector, but we only need the first cols entries // so truncate Q^T to cols X rows, so that Q^T x is only of length cols double[] y = new double[cols]; Blas2.dGemv(qtStore, 0, 1, rows, x, 0, 1, y, 0, 1, cols, rows); MatrixAlgorithms.SolveUpperRightTriangular(rStore, rows, cols, y, 0); return(new ColumnVector(y, cols)); }
/// <summary> /// Solve the system A x = b. /// </summary> /// <param name="rhs">The right-hand-side b.</param> /// <returns>The column vector x for which A x is closest to b.</returns> public ColumnVector Solve(IList <double> rhs) { if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } if (rhs.Count != rows) { throw new DimensionMismatchException(); } // copy rhs into an array, if necessary double[] x; if (rhs is double[]) { x = (double[])rhs; } else { x = new double[rows]; rhs.CopyTo(x, 0); } // Q^T x is a row-length vector, but we only need the first cols entries // so truncate Q^T to cols X rows, so that Q^T x is only of length cols double[] y = new double[cols]; Blas2.dGemv(qtStore, 0, 1, rows, x, 0, 1, y, 0, 1, cols, rows); MatrixAlgorithms.SolveUpperRightTriangular(rStore, rows, cols, y, 0); return(new ColumnVector(y, cols)); }
/// <summary> /// Computes the product of a rectangular matrix and a column vector. /// </summary> /// <param name="A">The matrix.</param> /// <param name="v">The column vector.</param> /// <returns>The column vector Av.</returns> /// <exception cref="ArgumentNullException"><paramref name="A"/> or <paramref name="v"/> is null.</exception> /// <exception cref="DimensionMismatchException">The column count of <paramref name="A"/> is not the same as the dimension of <paramref name="v"/>.</exception> public static ColumnVector operator *(RectangularMatrix A, ColumnVector v) { if (A == null) { throw new ArgumentNullException(nameof(A)); } if (v == null) { throw new ArgumentNullException(nameof(v)); } if (A.cols != v.dimension) { throw new DimensionMismatchException(); } double[] avStore = new double[A.rows]; Blas2.dGemv(A.store, A.offset, A.rowStride, A.colStride, v.store, v.offset, v.stride, avStore, 0, 1, A.rows, A.cols); return(new ColumnVector(avStore, A.rows)); }
// mixed arithmetic /// <summary> /// Computes the product of a square matrix and a column vector. /// </summary> /// <param name="A">The matrix.</param> /// <param name="v">The column vector.</param> /// <returns>The column vector Av.</returns> /// <exception cref="ArgumentNullException"><paramref name="A"/> or <paramref name="v"/> is null.</exception> /// <exception cref="DimensionMismatchException">The dimension of <paramref name="A"/> is not the same as the dimension of <paramref name="v"/>.</exception> public static ColumnVector operator *(SquareMatrix A, ColumnVector v) { if (A == null) { throw new ArgumentNullException("A"); } if (v == null) { throw new ArgumentNullException("v"); } if (A.dimension != v.dimension) { throw new DimensionMismatchException(); } double[] avStore = new double[A.dimension]; Blas2.dGemv(A.store, 0, 1, A.dimension, v.store, v.offset, v.stride, avStore, 0, 1, A.dimension, A.dimension); return(new ColumnVector(avStore, A.dimension)); }
/// <summary> /// Solves the system of equations Ax = b, where A is the original, square matrix. /// </summary> /// <param name="rhs">The right-hand-side vector b.</param> /// <returns>The solution vector x.</returns> /// <exception cref="ArgumentNullException"><paramref name="rhs"/> is null.</exception> /// <exception cref="DimensionMismatchException"><paramref name="rhs"/> does not have the same dimension as the original matrix.</exception> /// <exception cref="InvalidOperationException">The original matrix is not square.</exception> /// <remarks> /// <para>For singular and nearly-singular matrices, this method operates differently than other solution methods like /// <see cref="SquareQRDecomposition.Solve(IReadOnlyList{double})"/> and <see cref="LUDecomposition.Solve(IReadOnlyList{double})"/>. /// For singular and nearly-singular matrices, those methods /// tend to produce very large or even infinite solution components that delicately cancel to produce the required right-hand-side, /// but have little significance to the problem being modeled because they arise from inverting very small singular values /// of the original matrix that are dominated by floating point rounding errors. The SVD solution discards those singular /// values to obtain a solution vector driven by the dominant, non-singular parts of A. While this solution does not have /// the minimum achievable |Ax - b|, it is often more representative of the desired solution to the problem being modeled. /// </para> /// <para>For original matrices that are not singular or nearly-singular, this method will compute the same solution /// as other methods.</para> /// <para>This method is only available for square original matrices.</para> /// </remarks> public ColumnVector Solve(IReadOnlyList <double> rhs) { if (rows != cols) { throw new InvalidOperationException(); } if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } if (rhs.Count != cols) { throw new DimensionMismatchException(); } double[] x = new double[rows]; double[] y = new double[rows]; rhs.CopyTo(x, 0); Blas2.dGemv(utStore, 0, 1, rows, x, 0, 1, y, 0, 1, rows, rows); double minValue = tolerance * wStore[0]; for (int i = 0; i < wStore.Length; i++) { double w = wStore[i]; if (w > minValue) { y[i] /= w; } else { y[i] = 0.0; } } Array.Clear(x, 0, rows); Blas2.dGemv(vStore, 0, 1, rows, y, 0, 1, x, 0, 1, rows, rows); return(new ColumnVector(x, rows)); }