/// <summary> /// Solves the specified linear system of equations <i>Ax=b</i>. /// </summary> /// <param name="matrixA">The matrix A.</param> /// <param name="initialX"> /// The initial guess for x. If this value is <see langword="null"/>, a zero vector will be used /// as initial guess. /// </param> /// <param name="vectorB">The vector b.</param> /// <returns>The solution vector x.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="matrixA"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="vectorB"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="matrixA"/> is not a square matrix. /// </exception> /// <exception cref="ArgumentException"> /// The number of elements of <paramref name="initialX"/> does not match. /// </exception> public override VectorD Solve(MatrixD matrixA, VectorD initialX, VectorD vectorB) { NumberOfIterations = 0; if (matrixA == null) { throw new ArgumentNullException("matrixA"); } if (vectorB == null) { throw new ArgumentNullException("vectorB"); } if (matrixA.IsSquare == false) { throw new ArgumentException("Matrix A must be a square matrix.", "matrixA"); } if (matrixA.NumberOfRows != vectorB.NumberOfElements) { throw new ArgumentException("The number of rows of A and b do not match."); } if (initialX != null && initialX.NumberOfElements != vectorB.NumberOfElements) { throw new ArgumentException("The number of elements of the initial guess for x and b do not match."); } VectorD xOld = initialX ?? new VectorD(vectorB.NumberOfElements); VectorD xNew = new VectorD(vectorB.NumberOfElements); bool isConverged = false; // Make iterations until max iteration count or the result has converged. for (int i = 0; i < MaxNumberOfIterations && !isConverged; i++) { for (int j = 0; j < vectorB.NumberOfElements; j++) { double delta = 0; for (int k = 0; k < j; k++) { delta += matrixA[j, k] * xNew[k]; } for (int k = j + 1; k < vectorB.NumberOfElements; k++) { delta += matrixA[j, k] * xOld[k]; } delta = (vectorB[j] - delta) / matrixA[j, j]; xNew[j] = xOld[j] + RelaxationFactor * (delta - xOld[j]); } // Test convergence isConverged = VectorD.AreNumericallyEqual(xOld, xNew, Epsilon); xOld = xNew.Clone(); NumberOfIterations = i + 1; } return(xNew); }
/// <summary> /// 部分ピボット選択付きガウス消去法により連立一次方程式の解を求める /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> private static VectorD SolveByGEPP(MatrixD a, VectorD b) { int r = 0; int c = 0; var a2 = a.Clone(); var b2 = b.Clone(); while (r < a2.Rows - 1) { var maxA = a2.GetColumn(c).Where((x, i) => i >= r).Max(); var idxMaxA = a2.GetRowIndex((x, i) => (i >= r) && (x[c] == maxA)); if (idxMaxA != r) { a2.SwapRow(r, idxMaxA); b2.Swap(r, idxMaxA); } for (int i = r + 1; i < a2.Rows; i++) { var x = a2[i, c] * -1.0; a2[i, c] = 0; for (int j = c + 1; j < a2.Columns; j++) { a2[i, j] += a2[r, j] * (x / a2[r, c]); } b2[i] += b2[r] * (x / a2[r, c]); } r++; c++; } var n = b2.Length; var result = new VectorD(new double[n]); for (int k = n - 1; k >= 0; k--) { var sum = 0.0; for (int j = k + 1; j < n; j++) { sum += a2[k, j] * result[j]; } result[k] = (b2[k] - sum) / a2[k, k]; } return result; }
/// <summary> /// ガウス消去法により連立一次方程式の解を求める /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> private static VectorD SolveByGE(MatrixD a, VectorD b) { int r = 0; int c = 0; var a2 = a.Clone(); var b2 = b.Clone(); while (r < a2.Rows - 1) { for (int i = r + 1; i < a2.Rows; i++) { var x = a2[i, c] * -1.0; a2[i, c] = 0; for (int j = c + 1; j < a2.Columns; j++) { a2[i, j] += a2[r, j] * (x / a2[r, c]); } b2[i] += b2[r] * (x / a2[r, c]); } r++; c++; } var n = b2.Length; var result = new VectorD(new double[n]); for (int k = n - 1; k >= 0; k--) { var sum = 0.0; for (int j = k + 1; j < n; j++) { sum += a2[k, j] * result[j]; } result[k] = (b2[k] - sum) / a2[k, k]; } return result; }
/// <summary> /// Solves the specified linear system of equations <i>Ax=b</i>. /// </summary> /// <param name="matrixA">The matrix A.</param> /// <param name="initialX"> /// The initial guess for x. If this value is <see langword="null"/>, a zero vector will be used /// as initial guess. /// </param> /// <param name="vectorB">The vector b.</param> /// <returns>The solution vector x.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="matrixA"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="vectorB"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="matrixA"/> is not a square matrix. /// </exception> /// <exception cref="ArgumentException"> /// The number of elements of <paramref name="initialX"/> does not match. /// </exception> public override VectorD Solve(MatrixD matrixA, VectorD initialX, VectorD vectorB) { // TODO: We can possible improve the method by reordering after each step. // This can be done randomly or we sort by the "convergence" of the elements. // See book Physics-Based Animation. NumberOfIterations = 0; if (matrixA == null) { throw new ArgumentNullException("matrixA"); } if (vectorB == null) { throw new ArgumentNullException("vectorB"); } if (matrixA.IsSquare == false) { throw new ArgumentException("Matrix A must be a square matrix.", "matrixA"); } if (matrixA.NumberOfRows != vectorB.NumberOfElements) { throw new ArgumentException("The number of rows of A and b do not match."); } if (initialX != null && initialX.NumberOfElements != vectorB.NumberOfElements) { throw new ArgumentException("The number of elements of the initial guess for x and b do not match."); } VectorD xOld = initialX ?? new VectorD(vectorB.NumberOfElements); VectorD xNew = new VectorD(vectorB.NumberOfElements); bool isConverged = false; // Make iterations until max iteration count or the result has converged. for (int i = 0; i < MaxNumberOfIterations && !isConverged; i++) { for (int j = 0; j < vectorB.NumberOfElements; j++) { double delta = 0; for (int k = 0; k < j; k++) { delta += matrixA[j, k] * xOld[k]; } for (int k = j + 1; k < vectorB.NumberOfElements; k++) { delta += matrixA[j, k] * xOld[k]; } xNew[j] = (vectorB[j] - delta) / matrixA[j, j]; } // Test convergence isConverged = VectorD.AreNumericallyEqual(xOld, xNew, Epsilon); xOld = xNew.Clone(); NumberOfIterations = i + 1; } return(xNew); }
/// <summary> /// Solves the specified linear system of equations <i>Ax=b</i>. /// </summary> /// <param name="matrixA">The matrix A.</param> /// <param name="initialX"> /// The initial guess for x. If this value is <see langword="null"/>, a zero vector will be used /// as initial guess. /// </param> /// <param name="vectorB">The vector b.</param> /// <returns>The solution vector x.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="matrixA"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="vectorB"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="matrixA"/> is not a square matrix. /// </exception> /// <exception cref="ArgumentException"> /// The number of elements of <paramref name="initialX"/> does not match. /// </exception> public override VectorD Solve(MatrixD matrixA, VectorD initialX, VectorD vectorB) { // TODO: We can possible improve the method by reordering after each step. // This can be done randomly or we sort by the "convergence" of the elements. // See book Physics-Based Animation. NumberOfIterations = 0; if (matrixA == null) throw new ArgumentNullException("matrixA"); if (vectorB == null) throw new ArgumentNullException("vectorB"); if (matrixA.IsSquare == false) throw new ArgumentException("Matrix A must be a square matrix.", "matrixA"); if (matrixA.NumberOfRows != vectorB.NumberOfElements) throw new ArgumentException("The number of rows of A and b do not match."); if (initialX != null && initialX.NumberOfElements != vectorB.NumberOfElements) throw new ArgumentException("The number of elements of the initial guess for x and b do not match."); VectorD xOld = initialX ?? new VectorD(vectorB.NumberOfElements); VectorD xNew = new VectorD(vectorB.NumberOfElements); bool isConverged = false; // Make iterations until max iteration count or the result has converged. for (int i = 0; i < MaxNumberOfIterations && !isConverged; i++) { for (int j = 0; j < vectorB.NumberOfElements; j++) { double delta = 0; for (int k = 0; k < j; k++) delta += matrixA[j, k] * xNew[k]; for (int k = j + 1; k < vectorB.NumberOfElements; k++) delta += matrixA[j, k] * xOld[k]; xNew[j] = (vectorB[j] - delta) / matrixA[j, j]; } // Test convergence isConverged = VectorD.AreNumericallyEqual(xOld, xNew, Epsilon); xOld = xNew.Clone(); NumberOfIterations = i + 1; } return xNew; }
/// <summary> /// Solves the specified linear system of equations <i>Ax=b</i>. /// </summary> /// <param name="matrixA">The matrix A.</param> /// <param name="initialX"> /// The initial guess for x. If this value is <see langword="null"/>, a zero vector will be used /// as initial guess. /// </param> /// <param name="vectorB">The vector b.</param> /// <returns>The solution vector x.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="matrixA"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// <paramref name="vectorB"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// <paramref name="matrixA"/> is not a square matrix. /// </exception> /// <exception cref="ArgumentException"> /// The number of elements of <paramref name="initialX"/> does not match. /// </exception> public override VectorD Solve(MatrixD matrixA, VectorD initialX, VectorD vectorB) { NumberOfIterations = 0; if (matrixA == null) throw new ArgumentNullException("matrixA"); if (vectorB == null) throw new ArgumentNullException("vectorB"); if (matrixA.IsSquare == false) throw new ArgumentException("Matrix A must be a square matrix.", "matrixA"); if (matrixA.NumberOfRows != vectorB.NumberOfElements) throw new ArgumentException("The number of rows of A and b do not match."); if (initialX != null && initialX.NumberOfElements != vectorB.NumberOfElements) throw new ArgumentException("The number of elements of the initial guess for x and b do not match."); VectorD xOld = initialX ?? new VectorD(vectorB.NumberOfElements); VectorD xNew = new VectorD(vectorB.NumberOfElements); bool isConverged = false; // Make iterations until max iteration count or the result has converged. for (int i = 0; i < MaxNumberOfIterations && !isConverged; i++) { for (int j=0; j<vectorB.NumberOfElements; j++) { double delta = 0; for (int k=0; k < j; k++) delta += matrixA[j, k] * xNew[k]; for (int k=j+1; k < vectorB.NumberOfElements; k++) delta += matrixA[j, k] * xOld[k]; delta = (vectorB[j] - delta) / matrixA[j, j]; xNew[j] = xOld[j] + RelaxationFactor * (delta - xOld[j]); } // Test convergence isConverged = VectorD.AreNumericallyEqual(xOld, xNew, Epsilon); xOld = xNew.Clone(); NumberOfIterations = i + 1; } return xNew; }
public void CloneTest() { VectorD v = new VectorD(new List<double>(new double[] { 1, 2, 3, 4, 5 })); VectorD clonedVector = v.Clone(); Assert.AreEqual(v, clonedVector); }