/// <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 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)); }
internal IterativeStatistics Solve(IInterfaceFlexibilityMatrix matrix, IFetiPreconditioner preconditioner, IInterfaceProjection projector, Vector rhs, Vector lagrangeMultipliers) { int n = matrix.Order; int maxIterations = maxIterationsProvider.GetMaxIterations(matrix.Order); // r0 = d - F * λ0 var residual = matrix.Multiply(lagrangeMultipliers); residual.LinearCombinationIntoThis(-1.0, rhs, 1.0); // Other allocations var w = Vector.CreateZero(n); var y = Vector.CreateZero(n); var z = Vector.CreateZero(n); var direction = Vector.CreateZero(n); var matrixTimesDirection = Vector.CreateZero(n); double residualDotProductPrevious = double.NaN; double residualNormRatio = double.NaN; double beta = double.NaN; for (int iter = 1; iter <= maxIterations; ++iter) { // w(m-1) = P * r(m-1) projector.ProjectVector(residual, w, false); // z(m-1) = preconditioner * w(m-1) preconditioner.SolveLinearSystem(w, z); // Check convergence: usually if ||z|| / ||f|| < tolerance residualNormRatio = convergence.EstimateResidualNormRatio(lagrangeMultipliers, z); if (residualNormRatio <= residualTolerance) { //TODO: is it correct to check for convergence here? How many iterations should I return? return(new IterativeStatistics { AlgorithmName = name, HasConverged = true, NumIterationsRequired = iter - 1, //TODO: not sure about this. ResidualNormRatioEstimation = residualNormRatio }); } // y(m-1) = P * z(m-1) projector.ProjectVector(z, y, false); double residualDotProductCurrent = y.DotProduct(w); if (iter == 1) { // β(1) = 0 beta = 0; // p(1) = y0 direction.CopyFrom(y); } else { // β(m) = (y(m-1) * w(m-1)) / (y(m-2) * w(m-2)) beta = residualDotProductCurrent / residualDotProductPrevious; // p(m) = y(m-1) + β(m) * p(m-1), if m > 1 direction.LinearCombinationIntoThis(beta, y, 1.0); } residualDotProductPrevious = residualDotProductCurrent; // γ(m) = (y(m-1) * w(m-1)) / (p(m) * F * p(m)) matrix.Multiply(direction, matrixTimesDirection); double stepSize = (y * w) / (direction * matrixTimesDirection); // λ(m) = λ(m-1) + γ(m) * p(m) lagrangeMultipliers.AxpyIntoThis(direction, stepSize); // r(m) = r(m-1) -γ(m) * F * p(m) residual.AxpyIntoThis(matrixTimesDirection, -stepSize); } return(new IterativeStatistics { AlgorithmName = name, HasConverged = false, NumIterationsRequired = maxIterations, ResidualNormRatioEstimation = residualNormRatio }); }