public override IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs, IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer) { //TODO: find a better way to handle optimizations for the case x0=0, than using an initialGuessIsZero flag Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length); Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length); this.Matrix = matrix; this.Preconditioner = preconditioner; this.Rhs = rhs; // Initial solution and rhs (r = b - A * x) this.solution = solution; if (ReorthoCache.Directions.Count > 0) { if (!initialGuessIsZero) { solution.Clear(); } CalculateInitialSolutionFromStoredDirections(rhs, solution); residual = ExactResidual.Calculate(matrix, rhs, solution); } else // preferably call base method { // r = b - A * x if (initialGuessIsZero) { residual = rhs.Copy(); } else { residual = ExactResidual.Calculate(matrix, rhs, solution); } } // Initialize vectors //TODO: Pehaps I can just clear them from previous iterations precondResidual = zeroVectorInitializer(); direction = zeroVectorInitializer(); matrixTimesDirection = zeroVectorInitializer(); int maxIterations = MaxIterationsProvider.GetMaxIterations(matrix.NumColumns); return(SolveInternal(maxIterations, zeroVectorInitializer)); }
/// <summary> /// See <see cref="IPcgResidualUpdater.UpdateResidual(PcgAlgorithmBase, IVector)"/> /// </summary> public void UpdateResidual(PcgAlgorithmBase pcg, IVector residual) { //TODO: perhaps this should be done in an Initialize() method if (numIterationsBeforeCorrection == int.MinValue) { numIterationsBeforeCorrection = (int)Math.Floor(Math.Sqrt(pcg.Rhs.Length)); } if ((pcg.Iteration % numIterationsBeforeCorrection == 0) && (pcg.Iteration != 0)) //The first iteration uses the correct residual. { // Calculate the exact residual: r = b - A * x ExactResidual.Calculate(pcg.Matrix, pcg.Rhs, pcg.Solution, residual); } else { // Normally the residual vector is updated as: r = r - α * A*d residual.AxpyIntoThis(pcg.MatrixTimesDirection, -pcg.StepSize); } }
public void UpdateResidual(CGAlgorithm cg, IVector residual, out double resDotRes) { // Update the residual vector normally: r = r - α * A*d residual.AxpyIntoThis(cg.MatrixTimesDirection, -cg.StepSize); resDotRes = residual.DotProduct(residual); //TODO: it is weird that this sets resDotRes and cg.ResDotRes // Check if the CG will converge. TODO: Remove duplicate comutations: this check will also be done by CG later. double residualNormRatio = convergence.EstimateResidualNormRatio(cg); // let's pray that ICGResidualConvergence does not mutate any fields bool hasConverged = residualNormRatio <= residualTolerance; // Avoid premature convergence by calculating th exact residual. if (hasConverged) { // Exact residual: r = b - A * x ExactResidual.Calculate(cg.Matrix, cg.Rhs, cg.Solution, residual); // Recalculate the r * r resDotRes = residual.DotProduct(residual); } }
/// <summary> /// Solves the linear system A * x = b, where A = <paramref name="matrix"/> and b = <paramref name="rhs"/>. /// Initially x = <paramref name="initialGuess"/> and then it converges to the solution. /// </summary> /// <param name="matrix"> /// Represents the matrix A of the linear system A * x = b, which must be symmetric positive definite. /// </param> /// <param name="rhs"> /// The right hand side vector b of the linear system A * x = b. Constraints: /// <paramref name="rhs"/>.<see cref="IIndexable1D.Length"/> /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumRows"/>. /// </param> /// <param name="solution"> /// The vector from which to start refining the solution vector x. Constraints: /// <paramref name="solution"/>.<see cref="IIndexable1D.Length"/> /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumColumns"/>. /// </param> /// <param name="initialGuessIsZero"> /// If <paramref name="solution"/> is 0, then set <paramref name="initialGuessIsZero"/> to true to avoid performing the /// operation b-A*0 before starting. /// </param> /// <exception cref="NonMatchingDimensionsException"> /// Thrown if <paramref name="rhs"/> or <paramref name="solution"/> violate the described constraints. /// </exception> public IterativeStatistics Solve(ILinearTransformation matrix, IVectorView rhs, IVector solution, bool initialGuessIsZero) //TODO: find a better way to handle the case x0=0 { //TODO: these will also be checked by the matrix vector multiplication. Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length); Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length); this.Matrix = matrix; this.Rhs = rhs; this.solution = solution; // r = b - A * x if (initialGuessIsZero) { residual = rhs.Copy(); } else { residual = ExactResidual.Calculate(matrix, rhs, solution); } return(SolveInternal(maxIterationsProvider.GetMaxIterations(matrix.NumColumns))); }
/// <summary> /// Solves the linear system A * x = b by solving the preconditioned system inv(P) * A * inv(P)^T * y = inv(P) * b, /// where A = <paramref name="matrix"/>, b = <paramref name="rhsVector"/>, x is the solution, y = P^T * x, /// P*P^T = <paramref name="preconditioner"/>. /// Initially x = <paramref name="initialGuess"/> and then it converges to the solution. /// </summary> /// <param name="matrix"> /// Represents the matrix A of the linear system A * x = b, which must be symmetric positive definite. /// </param> /// <param name="rhs"> /// The right hand side vector b of the linear system A * x = b. Constraints: /// <paramref name="rhs"/>.<see cref="IIndexable1D.Length"/> /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumRows"/>. /// </param> /// <param name="preconditioner"> /// A preconditioner matrix that is also symmetric positive definite and has the same dimensions as A. /// </param> /// <param name="solution"> /// The vector from which to start refining the solution vector x. Constraints: /// <paramref name="solution"/>.<see cref="IIndexable1D.Length"/> /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumColumns"/>. /// </param> /// <param name="initialGuessIsZero"> /// If <paramref name="solution"/> is 0, then set <paramref name="initialGuessIsZero"/> to true to avoid performing the /// operation b-A*0 before starting. /// </param> /// <exception cref="NonMatchingDimensionsException"> /// Thrown if <paramref name="rhs"/> or <paramref name="solution"/> violate the described constraints. /// </exception> public virtual IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs, IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer) { //TODO: find a better way to handle optimizations for the case x0=0, than using an initialGuessIsZero flag Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length); Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length); this.Matrix = matrix; this.Preconditioner = preconditioner; this.Rhs = rhs; this.solution = solution; // r = b - A * x if (initialGuessIsZero) { residual = rhs.Copy(); } else { residual = ExactResidual.Calculate(matrix, rhs, solution); } return(SolveInternal(MaxIterationsProvider.GetMaxIterations(matrix.NumColumns), zeroVectorInitializer)); }
public IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs, IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer) { Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length); Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length); var innerIterations = innerIterationsProvider.GetMaxIterations(matrix.NumRows); IVector[] v = new Vector[innerIterations + 1]; var y = Vector.CreateZero(innerIterations + 1); var c = Vector.CreateZero(innerIterations + 1); var s = Vector.CreateZero(innerIterations + 1); var delta = 0.001; double residualNorm = double.MaxValue; var usedIterations = 0; if (initialGuessIsZero) { residual = rhs.Copy(); } else { residual = ExactResidual.Calculate(matrix, rhs, solution); } for (var iteration = 0; iteration < maximumIterations; iteration++) { preconditioner.SolveLinearSystem(residual, residual); //var residual = ExactResidual.Calculate(matrix, rhs, solution); residualNorm = residual.Norm2(); double residualTolerance; if (iteration == 0) { residualTolerance = residualNorm * relativeTolerance; } v[0] = residual.Scale(1 / residualNorm); var g = Vector.CreateZero(innerIterations + 1); g[0] = residualNorm; var hessenbergMatrix = Matrix.CreateZero(innerIterations + 1, innerIterations); var indexIteration = 0; for (int innerIteration = 0; innerIteration < innerIterations; innerIteration++) { indexIteration = innerIteration; v[innerIteration + 1] = Vector.CreateZero(v[innerIteration].Length); matrix.Multiply(v[innerIteration], v[innerIteration + 1]); preconditioner.SolveLinearSystem(v[innerIteration + 1], v[innerIteration + 1]); var av = v[innerIteration + 1].Norm2(); for (var j = 0; j <= innerIteration; j++) { hessenbergMatrix[j, innerIteration] = v[j].DotProduct(v[innerIteration + 1]); v[innerIteration + 1] = v[innerIteration + 1].Subtract(v[j].Scale(hessenbergMatrix[j, innerIteration])); } hessenbergMatrix[innerIteration + 1, innerIteration] = v[innerIteration + 1].Norm2(); if (Math.Abs(av + delta * hessenbergMatrix[innerIteration + 1, innerIteration] - av) < 10e-9) { for (int j = 0; j <= innerIteration; j++) { var htmp = v[j].DotProduct(v[innerIteration + 1]); hessenbergMatrix[j, innerIteration] += htmp; v[innerIteration + 1].LinearCombinationIntoThis(1.0, v[j], -htmp); } hessenbergMatrix[innerIteration + 1, innerIteration] = v[innerIteration + 1].Norm2(); } if (Math.Abs(hessenbergMatrix[innerIteration + 1, innerIteration]) > 10e-17) { v[innerIteration + 1].ScaleIntoThis(1 / hessenbergMatrix[innerIteration + 1, innerIteration]); } if (innerIteration > 0) { y = hessenbergMatrix.GetColumn(innerIteration).GetSubvector(0, innerIteration + 2); for (int i = 0; i <= innerIteration - 1; i++) { y = CalculateGivensRotation(c[i], s[i], i, y); } hessenbergMatrix.SetSubcolumn(innerIteration, y); } var mu = Math.Sqrt(hessenbergMatrix[innerIteration, innerIteration] * hessenbergMatrix[innerIteration, innerIteration] + hessenbergMatrix[innerIteration + 1, innerIteration] * hessenbergMatrix[innerIteration + 1, innerIteration]); c[innerIteration] = hessenbergMatrix[innerIteration, innerIteration] / mu; s[innerIteration] = -hessenbergMatrix[innerIteration + 1, innerIteration] / mu; hessenbergMatrix[innerIteration, innerIteration] = c[innerIteration] * hessenbergMatrix[innerIteration, innerIteration] - s[innerIteration] * hessenbergMatrix[innerIteration + 1, innerIteration]; hessenbergMatrix[innerIteration + 1, innerIteration] = 0.0; g = CalculateGivensRotation(c[innerIteration], s[innerIteration], innerIteration, g); residualNorm = Math.Abs(g[innerIteration + 1]); usedIterations++; if (residualNorm <= relativeTolerance && residualNorm <= absoluteTolerance) { break; } } indexIteration = indexIteration - 1; y[indexIteration + 1] = g[indexIteration + 1] / hessenbergMatrix[indexIteration + 1, indexIteration + 1]; for (int i = indexIteration; i >= 0; i--) { y[i] = (g[i] - (hessenbergMatrix.GetRow(i).GetSubvector(i + 1, indexIteration + 2) .DotProduct(y.GetSubvector(i + 1, indexIteration + 2)))) / hessenbergMatrix[i, i]; } for (int i = 0; i < matrix.NumRows; i++) { var subV = Vector.CreateZero(indexIteration + 2); for (int j = 0; j < indexIteration + 2; j++) { subV[j] = v[j][i]; } solution.Set(i, solution[i] + subV.DotProduct(y.GetSubvector(0, indexIteration + 2))); } if (residualNorm <= relativeTolerance && residualNorm <= absoluteTolerance) { break; } } return(new IterativeStatistics() { HasConverged = residualNorm <= relativeTolerance && residualNorm <= absoluteTolerance, AlgorithmName = name, NumIterationsRequired = usedIterations, ResidualNormRatioEstimation = residualNorm }); }