/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected override void CheckResult(IPreconditioner<float> preconditioner, SparseMatrix matrix, Vector<float> vector, Vector<float> result) { Assert.AreEqual(typeof (UnitPreconditioner<float>), preconditioner.GetType(), "#01"); // Unit preconditioner is doing nothing. Vector and result should be equal for (var i = 0; i < vector.Count; i++) { Assert.IsTrue(vector[i] == result[i], "#02-" + i); } }
/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected override void CheckResult(IPreconditioner<double> preconditioner, SparseMatrix matrix, Vector<double> vector, Vector<double> result) { Assert.AreEqual(typeof (DiagonalPreconditioner), preconditioner.GetType(), "#01"); // Compute M * result = product // compare vector and product. Should be equal var product = new DenseVector(result.Count); matrix.Multiply(result, product); for (var i = 0; i < product.Count; i++) { Assert.IsTrue(vector[i].AlmostEqualNumbersBetween(product[i], -Epsilon.Magnitude()), "#02-" + i); } }
/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected override void CheckResult(IPreconditioner<Complex32> preconditioner, SparseMatrix matrix, Vector<Complex32> vector, Vector<Complex32> result) { Assert.AreEqual(typeof(Diagonal), preconditioner.GetType(), "#01"); // Compute M * result = product // compare vector and product. Should be equal var product = new DenseVector(result.Count); matrix.Multiply(result, product); for (var i = 0; i < product.Count; i++) { Assert.IsTrue(vector[i].Real.AlmostEqual(product[i].Real, -Epsilon.Magnitude()), "#02-" + i); Assert.IsTrue(vector[i].Imaginary.AlmostEqual(product[i].Imaginary, -Epsilon.Magnitude()), "#03-" + i); } }
/// <summary> /// Solves the matrix equation AX = B, where A is the coefficient matrix (this matrix), B is the solution matrix and X is the unknown matrix. /// </summary> /// <param name="input">The solution matrix <c>B</c>.</param> /// <param name="solver">The iterative solver to use.</param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> /// <returns>The result matrix <c>X</c>.</returns> public Matrix <T> SolveIterative(Matrix <T> input, IIterativeSolver <T> solver, Iterator <T> iterator = null, IPreconditioner <T> preconditioner = null) { var result = Build.Dense(input.RowCount, input.ColumnCount); TrySolveIterative(input, result, solver, iterator, preconditioner); return(result); }
/// <summary> /// Solves the matrix equation AX = B, where A is the coefficient matrix (this matrix), B is the solution matrix and X is the unknown matrix. /// </summary> /// <param name="input">The solution matrix <c>B</c>.</param> /// <param name="result">The result matrix <c>X</c></param> /// <param name="solver">The iterative solver to use.</param> /// <param name="stopCriteria">Criteria to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public IterationStatus TrySolveIterative(Matrix <T> input, Matrix <T> result, IIterativeSolver <T> solver, IPreconditioner <T> preconditioner, params IIterationStopCriterion <T>[] stopCriteria) { var iterator = new Iterator <T>(stopCriteria.Length == 0 ? Build.IterativeSolverStopCriteria() : stopCriteria); return(TrySolveIterative(input, result, solver, iterator, preconditioner)); }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { BCGStabParametrs ConGradParametrs = solverParametrs as BCGStabParametrs; if (ConGradParametrs == null) { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in BSGStab"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in BSGSTab"); } else { int oIter = 0; double nPi, oPi, alpha, w, oNev, bNev, betta; oPi = alpha = w = 1; int size = rightPart.Size; Vector x, r, rTab, s, t, z, sqt, y; Vector v = new Vector(size); Vector p = new Vector(size); v.Nullify(); p.Nullify(); x = initialSolution; r = rightPart - matrix.SourceMatrix.Multiply(x); rTab = r; bNev = rightPart.Norm(); oNev = r.Norm() / bNev; solverLogger.AddIterationInfo(oIter, oNev);//logger if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by BSG Stab."); return x; } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by BSG Stab."); return x; } while (oIter < ConGradParametrs.MaxIterations && oNev > ConGradParametrs.Epsilon) { nPi = rTab * r; betta = (nPi / oPi) * (alpha / w); p = r + (p - v * w) * betta; y= matrix.QSolve(matrix.SSolve(p)); v = matrix.SourceMatrix.Multiply(y); alpha = nPi / (rTab * v); x = x + y * alpha;//УТОЧНИТЬ!!!!!!!!!!!!!!! s = r - v * alpha; if (s.Norm() / bNev < ConGradParametrs.Epsilon) return x; z = matrix.QSolve(matrix.SSolve(s)); t = matrix.SourceMatrix.Multiply(z); sqt = matrix.QSolve(matrix.SSolve(t)); w = (z * sqt) / (sqt * sqt); x = x + z * w;//УТОЧНИТЬ!!!!!!!!!!!!!!!!!!! r = s - t * w; oPi = nPi; oIter++; oNev = r.Norm() / bNev; if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by BSG Stab."); return x; } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by BSG Stab."); return x; } solverLogger.AddIterationInfo(oIter, oNev);//logger } return x; } }
/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected abstract void CheckResult(IPreconditioner <double> preconditioner, SparseMatrix matrix, Vector <double> vector, Vector <double> result);
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { if (solverParametrs is GaussSeidelParametrs) { GaussSeidelParametrs GZParametrs = solverParametrs as GaussSeidelParametrs; Vector x, xnext, r, di; int size, k; double Residual, w; Vector DEx, DEb, Dx, Fx, Ex; size = initialSolution.Size; x = new Vector(size); xnext = new Vector(size); r = new Vector(size); di = new Vector(size); x = initialSolution; w = GZParametrs.Relaxation; di = matrix.SourceMatrix.Diagonal; Dx = Vector.Mult(di, x); Fx = matrix.SourceMatrix.LMult(x, false); Ex = matrix.SourceMatrix.UMult(x, false); r = Dx + Fx + Ex - rightPart; var rpnorm = rightPart.Norm(); Residual = r.Norm() / rpnorm; DEb = Vector.Division(rightPart, di); solverLogger.AddIterationInfo(0, Residual); for (k = 1; k <= GZParametrs.MaxIterations && Residual > GZParametrs.Epsilon; k++) { DEx = Vector.Division(Ex + Fx, di); xnext = (DEb - DEx) * w + x * (1 - w); Ex = matrix.SourceMatrix.UMult(xnext, false); Dx = Vector.Mult(di, xnext); DEx = Vector.Division(Ex + Fx, di); x = xnext; xnext = (DEb - DEx) * w + x * (1 - w); Dx = Vector.Mult(di, xnext); Fx = matrix.SourceMatrix.LMult(xnext, false); r = Dx + Fx + Ex - rightPart; Residual = r.Norm() / rpnorm; if (System.Double.IsInfinity(Residual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by GaussSeidel ."); return(xnext); } if (System.Double.IsNaN(Residual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by GaussSeidel."); return(xnext); } solverLogger.AddIterationInfo(k, Residual); } return(xnext); } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GaussSeidel"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GaussSeidel"); } }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { if (solverParametrs is LOSParametrs) { LOSParametrs LOSParametrs = solverParametrs as LOSParametrs; Vector x, r, z, p; double alpha, betta; int size, k; double Residual,pp,rightnorm; Vector Ax; Vector LAU, Ur; size = initialSolution.Size; x = new Vector(size); r = new Vector(size); z = new Vector(size); p = new Vector(size); Ax = new Vector(size); LAU = new Vector(size); Ur = new Vector(size); x = initialSolution; Ax = matrix.SourceMatrix.Multiply(x); r = matrix.SSolve(rightPart - Ax); z = matrix.QSolve(r); p = matrix.SSolve(matrix.SourceMatrix.Multiply(z)); rightnorm = matrix.SSolve(rightPart).Norm(); Residual = r.Norm()/rightnorm; solverLogger.AddIterationInfo(0, Residual); for (k = 1; k <= LOSParametrs.MaxIterations && Residual > LOSParametrs.Epsilon; k++) { pp = p*p; alpha = (p * r) / pp; x = x + z * alpha; r = r - p * alpha; Ur = matrix.QSolve(r); LAU = matrix.SourceMatrix.Multiply(Ur); LAU = matrix.SSolve(LAU); betta = - (p * LAU) / pp; z = Ur + z * betta; p = LAU + p * betta; Residual = r.Norm() / rightnorm; if (System.Double.IsInfinity(Residual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by LOS."); return x; } if (System.Double.IsNaN(Residual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by LOS."); return x; } solverLogger.AddIterationInfo(k, Residual); } return x; } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GaussSeidel"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GaussSeidel"); } }
private void InitializeSolver() { result = Vector<double>.Build.Dense(n * m); Control.LinearAlgebraProvider = new OpenBlasLinearAlgebraProvider(); //Control.UseNativeMKL(); //Control.LinearAlgebraProvider = new MklLinearAlgebraProvider(); //Control.UseManaged(); var iterationCountStopCriterion = new IterationCountStopCriterion<double>(1000); var residualStopCriterion = new ResidualStopCriterion<double>(1e-7); monitor = new Iterator<double>(iterationCountStopCriterion, residualStopCriterion); solver = new BiCgStab(); preconditioner = new MILU0Preconditioner(); }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { GMRESParameters GMRESParameters = solverParametrs as GMRESParameters; if (GMRESParameters != null) { Vector[] V, H; Vector residual, x, d, z, w, tmp; bool continueCalculations; double epsilon = GMRESParameters.Epsilon; int m = GMRESParameters.M; int maxIterations = GMRESParameters.MaxIterations; int n = rightPart.Size; x = initialSolution; residual = rightPart - matrix.SourceMatrix.Multiply(x); residual = matrix.SSolve(residual); double rightPartNorm = matrix.SSolve(rightPart).Norm(); double residualNorm = residual.Norm(); if (System.Double.IsInfinity(residualNorm / rightPartNorm)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by GMRES."); return x; } if (System.Double.IsNaN(residualNorm / rightPartNorm)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by GMRES."); return x; } x = matrix.QMultiply(initialSolution); V = new Vector[m]; for (int i = 0; i < m; i++) V[i] = new Vector(n); H = new Vector[m]; for (int i = 0; i < m; i++) H[i] = new Vector(m + 1); d = new Vector(m + 1); for (int k = 1; k <= maxIterations && residualNorm / rightPartNorm > epsilon; k++) { d.Nullify(); V[0] = residual * (1.0 / residualNorm); continueCalculations = true; for (int j = 1; j <= m && continueCalculations; j++) { tmp = matrix.QSolve(V[j - 1]); w = matrix.SSolve(matrix.SourceMatrix.Multiply(tmp)); for (int l = 1; l <= j; l++) { H[j - 1][l - 1] = V[l - 1] * w; w = w - V[l - 1] * H[j - 1][l - 1]; } H[j - 1][j] = w.Norm(); if (Math.Abs(H[j - 1][j]) < 1e-10) { m = j; continueCalculations = false; } else { if(j != m) V[j] = w * (1.0 / H[j - 1][j]); } } d[0] = residualNorm; z = solveMinSqrProblem(d, H, m); x = x + multiplyMatrixVector(z, V); tmp = rightPart - matrix.SourceMatrix.Multiply(matrix.QSolve(x)); residual = matrix.SSolve(tmp); residualNorm = residual.Norm(); if (System.Double.IsInfinity(residualNorm / rightPartNorm)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by GMRES."); return x; } if (System.Double.IsNaN(residualNorm / rightPartNorm)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by GMRES."); return x; } solverLogger.AddIterationInfo(k, residualNorm / rightPartNorm); } return matrix.QSolve(x); } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GMRES"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GMRES"); } }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { if (solverParametrs is GaussSeidelParametrs) { GaussSeidelParametrs GZParametrs = solverParametrs as GaussSeidelParametrs; Vector x,xnext, r, di; int size, k; double Residual, w; Vector DEx,DEb, Dx, Fx, Ex; size = initialSolution.Size; x = new Vector(size); xnext = new Vector(size); r = new Vector(size); di = new Vector(size); x = initialSolution; w = GZParametrs.Relaxation; di = matrix.SourceMatrix.Diagonal; Dx = Vector.Mult(di, x); Fx = matrix.SourceMatrix.LMult(x, false); Ex = matrix.SourceMatrix.UMult(x, false); r = Dx+Fx+ Ex - rightPart; var rpnorm = rightPart.Norm(); Residual = r.Norm() / rpnorm; DEb = Vector.Division(rightPart,di); solverLogger.AddIterationInfo(0, Residual); for (k = 1; k <= GZParametrs.MaxIterations && Residual > GZParametrs.Epsilon; k++) { DEx = Vector.Division(Ex+Fx,di); xnext = (DEb - DEx) * w + x * (1 - w); Ex = matrix.SourceMatrix.UMult(xnext, false); Dx = Vector.Mult(di, xnext); DEx = Vector.Division(Ex + Fx, di); x = xnext; xnext = (DEb - DEx) * w + x * (1 - w); Dx = Vector.Mult(di, xnext); Fx = matrix.SourceMatrix.LMult(xnext, false); r = Dx + Fx + Ex - rightPart; Residual = r.Norm() / rpnorm; if (System.Double.IsInfinity(Residual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by GaussSeidel ."); return xnext; } if (System.Double.IsNaN(Residual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by GaussSeidel."); return xnext; } solverLogger.AddIterationInfo(k, Residual); } return xnext; } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GaussSeidel"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GaussSeidel"); } }
/// <summary> /// Решение СЛАУ методом сопряженных градиентов /// </summary> /// <param name="A">Матрица СЛАУ</param> /// <param name="b">Ветор правой части</param> /// <param name="Initial">Ветор начального приближения</param> /// <param name="Precision">Точность</param> /// <param name="Maxiter">Максимальное число итераций</param> /// <returns>Вектор x - решение СЛАУ Ax=b с заданной точностью</returns> public IVector Solve(IPreconditioner Preconditioner, IMatrix A, IVector b, IVector Initial, double Precision, int Maxiter, ILogger Logger) { Logger.WriteNameSolution("MSG", Preconditioner.getName()); string start = DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff"); Logger.setMaxIter(Maxiter); IVector x = Preconditioner.MultU(Initial); double scalAzZ, scalRR, alpha, beta = 1.0; IVector r = b.Add(A.Mult(Initial), 1, -1); r = Preconditioner.T.SolveL(Preconditioner.SolveL(r)); IVector Az, Atz, z = A.Transpose.Mult(r); z = Preconditioner.T.SolveU(z); r = z.Clone() as IVector; scalRR = r.ScalarMult(r); double normR = Math.Sqrt(scalRR) / b.Norm; for (int iter = 0; iter < Maxiter && normR > Precision && beta > 0; iter++) { Az = Preconditioner.SolveU(z); Atz = A.Mult(Az); Atz = Preconditioner.T.SolveL(Preconditioner.SolveL(Atz)); Az = A.Transpose.Mult(Atz); Az = Preconditioner.T.SolveU(Az); scalAzZ = Az.ScalarMult(z); if (scalAzZ == 0) { Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); throw new DivideByZeroException("Division by 0"); } alpha = scalRR / scalAzZ; x.Add(z, 1, alpha, true); r.Add(Az, 1, -alpha, true); beta = scalRR; if (scalRR == 0) { Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); throw new DivideByZeroException("Division by 0"); } scalRR = r.ScalarMult(r); beta = scalRR / beta; z = r.Add(z, 1, beta); normR = Math.Sqrt(scalRR) / b.Norm; Factory.Residual.Add(normR); Logger.WriteIteration(iter, normR); if (double.IsNaN(normR) || double.IsInfinity(normR)) { x = Preconditioner.SolveU(x); Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); throw new CantSolveException(); } } ; x = Preconditioner.SolveU(x); Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); return(x); }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param> /// <param name="input">The solution <see cref="Vector"/>, <c>b</c>.</param> /// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public void Solve(Matrix <double> matrix, Vector <double> input, Vector <double> result, Iterator <double> iterator, IPreconditioner <double> preconditioner) { var A = (SparseMatrix)matrix; var M = preconditioner; var b = (DenseVector)input; var x = (DenseVector)result; double atolf = 0.0; double rtol_1 = 0.0; int recompute_residual_p = 0; var p = new DenseVector(b.Count); var s = new DenseVector(b.Count); var r = new DenseVector(b.Count); double alpha, beta; double gamma, gamma_old; double bi_prod; double sdotp; bool recompute_true_residual = false; int i = 0; M.Initialize(A); // Start pcg solve // bi_prod = <C*b,b> //VectorHelper.Clear(p); M.Approximate(input, p); bi_prod = VectorHelper.DotProduct(p, b); if (bi_prod > 0.0) { if (atolf > 0) // mixed relative and absolute tolerance { bi_prod += atolf; } } else // bi_prod==0.0: the rhs vector b is zero { // Set x equal to zero and return VectorHelper.Copy(b, x); return; } // r = b - Ax VectorHelper.Copy(b, r); A.Multiply(-1.0, result, 1.0, r); // p = C*r //VectorHelper.Clear(p); M.Approximate(r, p); // gamma = <r,p> gamma = VectorHelper.DotProduct(r, p); while (iterator.DetermineStatus(i, x, b, r) == IterationStatus.Continue) { // the core CG calculations... i++; // At user request, periodically recompute the residual from the formula // r = b - A x (instead of using the recursive definition). Note that this // is potentially expensive and can lead to degraded convergence (since it // essentially a "restarted CG"). recompute_true_residual = (recompute_residual_p > 0) && !((i % recompute_residual_p) == 0); // s = A*p A.Multiply(1.0, p, 0.0, s); // alpha = gamma / <s,p> sdotp = VectorHelper.DotProduct(s, p); if (sdotp == 0.0) { throw new NumericalBreakdownException(); } alpha = gamma / sdotp; gamma_old = gamma; // x = x + alpha*p VectorHelper.Add(alpha, p, x, x); // r = r - alpha*s if (recompute_true_residual) { //Recomputing the residual... VectorHelper.Copy(b, r); A.Multiply(-1.0, result, 1.0, r); } else { VectorHelper.Add(-alpha, s, r, r); } // s = C*r VectorHelper.Clear(s); M.Approximate(r, s); // gamma = <r,s> gamma = VectorHelper.DotProduct(r, s); // residual-based stopping criteria: ||r_new-r_old||_C < rtol ||b||_C if (rtol_1 > 0) { // use that ||r_new-r_old||_C^2 = (r_new ,C r_new) + (r_old, C r_old) if ((gamma + gamma_old) / bi_prod < rtol_1 * rtol_1) { break; } } // ... gamma should be >=0. IEEE subnormal numbers are < 2**(-1022)=2.2e-308 // (and >= 2**(-1074)=4.9e-324). So a gamma this small means we're getting // dangerously close to subnormal or zero numbers (usually if gamma is small, // so will be other variables). Thus further calculations risk a crash. // Such small gamma generally means no hope of progress anyway. if (Math.Abs(gamma) < TINY) { throw new NumericalBreakdownException(); } // beta = gamma / gamma_old beta = gamma / gamma_old; // p = s + beta p if (recompute_true_residual) { VectorHelper.Copy(s, p); } else { p.Scale(beta); VectorHelper.Add(1.0, s, p, p); } } }
/// <summary> /// Решение СЛАУ методом локально-оптимальной схемы /// </summary> /// <param name="preconditioner">Матрица СЛАУ</param> /// <param name="b">Ветор правой части</param> /// <param name="Initial">Ветор начального приближения</param> /// <param name="Precision">Точность</param> /// <param name="Maxiter">Максимальное число итераций</param> /// <returns>Вектор x - решение СЛАУ Ax=b с заданной точностью</returns> public IVector Solve(IPreconditioner preconditioner, IMatrix A, IVector b, IVector Initial, double Precision, int Maxiter, ILogger Logger) { Logger.WriteNameSolution("LOS", preconditioner.getName()); string start = DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff"); Logger.setMaxIter(Maxiter); IVector x = Initial.Clone() as IVector; double alpha = 0.0, beta = 0.0; IVector r = b.Add(A.Mult(Initial), 1, -1); //r_0 = f - Ax_0 r = preconditioner.SolveL(r); // r_0 = L^-1 * (f - Ax_0) IVector Ar, z = preconditioner.SolveU(r); // z_0 = U^-1 * r_0 IVector p = preconditioner.SolveL(A.Mult(z)); // p_0 = L^-1 * Az_0 double p_r = 0.0, p_p = 0.0; double scalRR = r.ScalarMult(r); double normR = Math.Sqrt(scalRR) / b.Norm; for (int iter = 0; iter < Maxiter && normR > Precision; iter++) //for (int iter = 0; iter < Maxiter && ; iter++) { p_r = p.ScalarMult(r); //(p_k-1,r_k-1) p_p = p.ScalarMult(p); //(p_k-1,p_k-1) alpha = p_r / p_p; x.Add(z, 1, alpha, true); // x_k = x_k-1 + alfa_k*z_k-1 r.Add(p, 1, -alpha, true); // r_k = r_k-1 - alfa_k*p_k-1 Ar = preconditioner.SolveL(A.Mult(preconditioner.SolveU(r))); //Ar_k = L^-1 * A * U^-1 * r_k //Ar = A.SolveU(r); //Ar = AA.Mult(Ar); //Ar = A.SolveL(Ar); beta = -(p.ScalarMult(Ar) / p_p); z = preconditioner.SolveU(r).Add(z, 1, beta); //z_k = U^-1 * r_k + beta_k*z_k-1 p = Ar.Add(p, 1, beta); // p_k = L^-1 * A * U^-1 * r_k + beta_k*p_k-1 if (scalRR == 0) { Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); throw new DivideByZeroException("Division by 0"); } scalRR = r.ScalarMult(r); normR = Math.Sqrt(scalRR) / b.Norm; Factory.Residual.Add(normR); Logger.WriteIteration(iter, normR); if (double.IsNaN(normR) || double.IsInfinity(normR)) { Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); throw new CantSolveException(); } } Logger.WriteSolution(x, Maxiter, b.Add(A.Mult(x), -1, 1).Norm); Logger.WriteTime(start, DateTime.Now.ToString("dd.MM.yyyy hh:mm:ss:fff")); return(x); }
/// <summary> /// Solves the matrix equation AX = B, where A is the coefficient matrix (this matrix), B is the solution matrix and X is the unknown matrix. /// </summary> /// <param name="input">The solution matrix <c>B</c>.</param> /// <param name="solver">The iterative solver to use.</param> /// <param name="stopCriteria">Criteria to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> /// <returns>The result matrix <c>X</c>.</returns> public Matrix <T> SolveIterative(Matrix <T> input, IIterativeSolver <T> solver, IPreconditioner <T> preconditioner, params IIterationStopCriterion <T>[] stopCriteria) { var result = Build.Dense(input.RowCount, input.ColumnCount); TrySolveIterative(input, result, solver, preconditioner, stopCriteria); return(result); }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { JacobiParametrs JacParametrs = solverParametrs as JacobiParametrs; if (JacParametrs != null) { Vector x, r, diagonal; int size, k; double relativeResidual, w, rightPartNorm; Vector Db, Dx, Lx, Ux, DULx; size = initialSolution.Size; x = new Vector(size); r = new Vector(size); diagonal = new Vector(size); x = initialSolution; w = JacParametrs.Relaxation; diagonal = matrix.SourceMatrix.Diagonal; rightPartNorm = rightPart.Norm(); Dx = Vector.Mult(diagonal, x); Lx = matrix.SourceMatrix.LMult(x, false); Ux = matrix.SourceMatrix.UMult(x, false); r = Lx + Dx + Ux - rightPart; relativeResidual = r.Norm() / rightPartNorm; if (System.Double.IsInfinity(relativeResidual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by Jacobi."); return(x); } if (System.Double.IsNaN(relativeResidual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by Jacobi."); return(x); } Db = Vector.Division(rightPart, diagonal); solverLogger.AddIterationInfo(0, relativeResidual); for (k = 1; k <= solverParametrs.MaxIterations && relativeResidual > solverParametrs.Epsilon; k++) { DULx = Vector.Division(Ux + Lx, diagonal); x = (Db - DULx) * w + x * (1 - w); Dx = Vector.Mult(diagonal, x); Lx = matrix.SourceMatrix.LMult(x, false); Ux = matrix.SourceMatrix.UMult(x, false); r = Lx + Dx + Ux - rightPart; relativeResidual = r.Norm() / rightPartNorm; if (System.Double.IsInfinity(relativeResidual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by Jacobi."); return(x); } if (System.Double.IsNaN(relativeResidual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by Jacobi."); return(x); } solverLogger.AddIterationInfo(k, relativeResidual); } return(x); } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in Jacobi"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in Jacobi"); } }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient matrix, <c>A</c>.</param> /// <param name="input">The solution vector, <c>b</c></param> /// <param name="result">The result vector, <c>x</c></param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public void Solve(Matrix <Numerics.Complex32> matrix, Vector <Numerics.Complex32> input, Vector <Numerics.Complex32> result, Iterator <Numerics.Complex32> iterator, IPreconditioner <Numerics.Complex32> preconditioner) { if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare, nameof(matrix)); } if (result.Count != input.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (input.Count != matrix.RowCount) { throw Matrix.DimensionsDontMatch <ArgumentException>(input, matrix); } if (iterator == null) { iterator = new Iterator <Numerics.Complex32>(); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <Numerics.Complex32>(); } preconditioner.Initialize(matrix); var d = new DenseVector(input.Count); var r = DenseVector.OfVector(input); var uodd = new DenseVector(input.Count); var ueven = new DenseVector(input.Count); var v = new DenseVector(input.Count); var pseudoResiduals = DenseVector.OfVector(input); var x = new DenseVector(input.Count); var yodd = new DenseVector(input.Count); var yeven = DenseVector.OfVector(input); // Temp vectors var temp = new DenseVector(input.Count); var temp1 = new DenseVector(input.Count); var temp2 = new DenseVector(input.Count); // Define the scalars Numerics.Complex32 alpha = 0; Numerics.Complex32 eta = 0; float theta = 0; // Initialize var tau = (float)input.L2Norm(); Numerics.Complex32 rho = tau * tau; // Calculate the initial values for v // M temp = yEven preconditioner.Approximate(yeven, temp); // v = A temp matrix.Multiply(temp, v); // Set uOdd v.CopyTo(ueven); // Start the iteration var iterationNumber = 0; while (iterator.DetermineStatus(iterationNumber, result, input, pseudoResiduals) == IterationStatus.Continue) { // First part of the step, the even bit if (IsEven(iterationNumber)) { // sigma = (v, r) var sigma = r.ConjugateDotProduct(v); if (sigma.Real.AlmostEqualNumbersBetween(0, 1) && sigma.Imaginary.AlmostEqualNumbersBetween(0, 1)) { // FAIL HERE iterator.Cancel(); break; } // alpha = rho / sigma alpha = rho / sigma; // yOdd = yEven - alpha * v v.Multiply(-alpha, temp1); yeven.Add(temp1, yodd); // Solve M temp = yOdd preconditioner.Approximate(yodd, temp); // uOdd = A temp matrix.Multiply(temp, uodd); } // The intermediate step which is equal for both even and // odd iteration steps. // Select the correct vector var uinternal = IsEven(iterationNumber) ? ueven : uodd; var yinternal = IsEven(iterationNumber) ? yeven : yodd; // pseudoResiduals = pseudoResiduals - alpha * uOdd uinternal.Multiply(-alpha, temp1); pseudoResiduals.Add(temp1, temp2); temp2.CopyTo(pseudoResiduals); // d = yOdd + theta * theta * eta / alpha * d d.Multiply(theta * theta * eta / alpha, temp); yinternal.Add(temp, d); // theta = ||pseudoResiduals||_2 / tau theta = (float)pseudoResiduals.L2Norm() / tau; var c = 1 / (float)Math.Sqrt(1 + (theta * theta)); // tau = tau * theta * c tau *= theta * c; // eta = c^2 * alpha eta = c * c * alpha; // x = x + eta * d d.Multiply(eta, temp1); x.Add(temp1, temp2); temp2.CopyTo(x); // Check convergence and see if we can bail if (iterator.DetermineStatus(iterationNumber, result, input, pseudoResiduals) != IterationStatus.Continue) { // Calculate the real values preconditioner.Approximate(x, result); // Calculate the true residual. Use the temp vector for that // so that we don't pollute the pseudoResidual vector for no // good reason. CalculateTrueResidual(matrix, temp, result, input); // Now recheck the convergence if (iterator.DetermineStatus(iterationNumber, result, input, temp) != IterationStatus.Continue) { // We're all good now. return; } } // The odd step if (!IsEven(iterationNumber)) { if (rho.Real.AlmostEqualNumbersBetween(0, 1) && rho.Imaginary.AlmostEqualNumbersBetween(0, 1)) { // FAIL HERE iterator.Cancel(); break; } var rhoNew = r.ConjugateDotProduct(pseudoResiduals); var beta = rhoNew / rho; // Update rho for the next loop rho = rhoNew; // yOdd = pseudoResiduals + beta * yOdd yodd.Multiply(beta, temp1); pseudoResiduals.Add(temp1, yeven); // Solve M temp = yOdd preconditioner.Approximate(yeven, temp); // uOdd = A temp matrix.Multiply(temp, ueven); // v = uEven + beta * (uOdd + beta * v) v.Multiply(beta, temp1); uodd.Add(temp1, temp); temp.Multiply(beta, temp1); ueven.Add(temp1, v); } // Calculate the real values preconditioner.Approximate(x, result); iterationNumber++; } }
public PCG(IPreconditioner <double> M) { this.Preconditioner = M; }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { JacobiParametrs JacParametrs = solverParametrs as JacobiParametrs; if (JacParametrs != null) { Vector x, r, diagonal; int size, k; double relativeResidual, w, rightPartNorm; Vector Db, Dx, Lx, Ux, DULx; size = initialSolution.Size; x = new Vector(size); r = new Vector(size); diagonal = new Vector(size); x = initialSolution; w = JacParametrs.Relaxation; diagonal = matrix.SourceMatrix.Diagonal; rightPartNorm = rightPart.Norm(); Dx = Vector.Mult(diagonal, x); Lx = matrix.SourceMatrix.LMult(x, false); Ux = matrix.SourceMatrix.UMult(x, false); r = Lx + Dx + Ux - rightPart; relativeResidual = r.Norm() / rightPartNorm; if (System.Double.IsInfinity(relativeResidual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by Jacobi."); return x; } if (System.Double.IsNaN(relativeResidual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by Jacobi."); return x; } Db = Vector.Division(rightPart, diagonal); solverLogger.AddIterationInfo(0, relativeResidual); for (k = 1; k <= solverParametrs.MaxIterations && relativeResidual > solverParametrs.Epsilon; k++) { DULx = Vector.Division(Ux + Lx, diagonal); x = (Db - DULx) * w + x * (1 - w); Dx = Vector.Mult(diagonal, x); Lx = matrix.SourceMatrix.LMult(x, false); Ux = matrix.SourceMatrix.UMult(x, false); r = Lx + Dx + Ux - rightPart; relativeResidual = r.Norm() / rightPartNorm; if (System.Double.IsInfinity(relativeResidual)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by Jacobi."); return x; } if (System.Double.IsNaN(relativeResidual)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by Jacobi."); return x; } solverLogger.AddIterationInfo(k, relativeResidual); } return x; } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in Jacobi"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in Jacobi"); } }
public abstract Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs);
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { GMRESParameters GMRESParameters = solverParametrs as GMRESParameters; if (GMRESParameters != null) { Vector[] V, H; Vector residual, x, d, z, w, tmp; bool continueCalculations; double epsilon = GMRESParameters.Epsilon; int m = GMRESParameters.M; int maxIterations = GMRESParameters.MaxIterations; int n = rightPart.Size; x = initialSolution; residual = rightPart - matrix.SourceMatrix.Multiply(x); residual = matrix.SSolve(residual); double rightPartNorm = matrix.SSolve(rightPart).Norm(); double residualNorm = residual.Norm(); if (System.Double.IsInfinity(residualNorm / rightPartNorm)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by GMRES."); return(x); } if (System.Double.IsNaN(residualNorm / rightPartNorm)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by GMRES."); return(x); } x = matrix.QMultiply(initialSolution); V = new Vector[m]; for (int i = 0; i < m; i++) { V[i] = new Vector(n); } H = new Vector[m]; for (int i = 0; i < m; i++) { H[i] = new Vector(m + 1); } d = new Vector(m + 1); for (int k = 1; k <= maxIterations && residualNorm / rightPartNorm > epsilon; k++) { d.Nullify(); V[0] = residual * (1.0 / residualNorm); continueCalculations = true; for (int j = 1; j <= m && continueCalculations; j++) { tmp = matrix.QSolve(V[j - 1]); w = matrix.SSolve(matrix.SourceMatrix.Multiply(tmp)); for (int l = 1; l <= j; l++) { H[j - 1][l - 1] = V[l - 1] * w; w = w - V[l - 1] * H[j - 1][l - 1]; } H[j - 1][j] = w.Norm(); if (Math.Abs(H[j - 1][j]) < 1e-10) { m = j; continueCalculations = false; } else { if (j != m) { V[j] = w * (1.0 / H[j - 1][j]); } } } d[0] = residualNorm; z = solveMinSqrProblem(d, H, m); x = x + multiplyMatrixVector(z, V); tmp = rightPart - matrix.SourceMatrix.Multiply(matrix.QSolve(x)); residual = matrix.SSolve(tmp); residualNorm = residual.Norm(); if (System.Double.IsInfinity(residualNorm / rightPartNorm)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by GMRES."); return(x); } if (System.Double.IsNaN(residualNorm / rightPartNorm)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by GMRES."); return(x); } solverLogger.AddIterationInfo(k, residualNorm / rightPartNorm); } return(matrix.QSolve(x)); } else { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GMRES"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in GMRES"); } }
/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected abstract void CheckResult(IPreconditioner<double> preconditioner, SparseMatrix matrix, Vector<double> vector, Vector<double> result);
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient matrix, <c>A</c>.</param> /// <param name="input">The solution vector, <c>b</c></param> /// <param name="result">The result vector, <c>x</c></param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public void Solve(Matrix <float> matrix, Vector <float> input, Vector <float> result, Iterator <float> iterator, IPreconditioner <float> preconditioner) { if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resource.ArgumentMatrixSquare, "matrix"); } if (result.Count != input.Count) { throw new ArgumentException(Resource.ArgumentVectorsSameLength); } if (iterator == null) { iterator = new Iterator <float>(); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <float>(); } // Create a copy of the solution and result vectors so we can use them // later on var internalInput = input.Clone(); var internalResult = result.Clone(); foreach (var solver in _solvers) { // Store a reference to the solver so we can stop it. IterationStatus status; try { // Reset the iterator and pass it to the solver iterator.Reset(); // Start the solver solver.Item1.Solve(matrix, internalInput, internalResult, iterator, solver.Item2 ?? preconditioner); status = iterator.Status; } catch (Exception) { // The solver broke down. // Log a message about this // Switch to the next preconditioner. // Reset the solution vector to the previous solution input.CopyTo(internalInput); continue; } // There was no fatal breakdown so check the status if (status == IterationStatus.Converged) { // We're done internalResult.CopyTo(result); break; } // We're not done // Either: // - calculation finished without convergence if (status == IterationStatus.StoppedWithoutConvergence) { // Copy the internal result to the result vector and // continue with the calculation. internalResult.CopyTo(result); } else { // - calculation failed --> restart with the original vector // - calculation diverged --> restart with the original vector // - Some unknown status occurred --> To be safe restart. input.CopyTo(internalInput); } } }
// Iterative Solvers: Full /// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix (this matrix), b is the solution vector and x is the unknown vector. /// </summary> /// <param name="input">The solution vector <c>b</c>.</param> /// <param name="result">The result vector <c>x</c>.</param> /// <param name="solver">The iterative solver to use.</param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public IterationStatus TrySolveIterative(Vector <T> input, Vector <T> result, IIterativeSolver <T> solver, Iterator <T> iterator = null, IPreconditioner <T> preconditioner = null) { if (iterator == null) { iterator = new Iterator <T>(Build.IterativeSolverStopCriteria()); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <T>(); } solver.Solve(this, input, result, iterator, preconditioner); return(iterator.Status); }
/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected abstract void CheckResult(IPreconditioner <Complex> preconditioner, SparseMatrix matrix, Vector <Complex> vector, Vector <Complex> result);
public override void HandleMatrixWillBeSet() { mustUpdatePreconditioner = true; preconditioner = null; }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param> /// <param name="input">The solution <see cref="Vector"/>, <c>b</c>.</param> /// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public void Solve(Matrix <Complex> matrix, Vector <Complex> input, Vector <Complex> result, Iterator <Complex> iterator, IPreconditioner <Complex> preconditioner) { if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); } if (result.Count != input.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (input.Count != matrix.RowCount) { throw Matrix.DimensionsDontMatch <ArgumentException>(input, result); } if (iterator == null) { iterator = new Iterator <Complex>(); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <Complex>(); } preconditioner.Initialize(matrix); // Compute r_0 = b - Ax_0 for some initial guess x_0 // In this case we take x_0 = vector // This is basically a SAXPY so it could be made a lot faster var residuals = new DenseVector(matrix.RowCount); CalculateTrueResidual(matrix, residuals, result, input); // Choose r~ (for example, r~ = r_0) var tempResiduals = residuals.Clone(); // create seven temporary vectors needed to hold temporary // coefficients. All vectors are mangled in each iteration. // These are defined here to prevent stressing the garbage collector var vecP = new DenseVector(residuals.Count); var vecPdash = new DenseVector(residuals.Count); var nu = new DenseVector(residuals.Count); var vecS = new DenseVector(residuals.Count); var vecSdash = new DenseVector(residuals.Count); var temp = new DenseVector(residuals.Count); var temp2 = new DenseVector(residuals.Count); // create some temporary double variables that are needed // to hold values in between iterations Complex currentRho = 0; Complex alpha = 0; Complex omega = 0; var iterationNumber = 0; while (iterator.DetermineStatus(iterationNumber, result, input, residuals) == IterationStatus.Continue) { // rho_(i-1) = r~^T r_(i-1) // dotproduct r~ and r_(i-1) var oldRho = currentRho; currentRho = tempResiduals.ConjugateDotProduct(residuals); // if (rho_(i-1) == 0) // METHOD FAILS // If rho is only 1 ULP from zero then we fail. if (currentRho.Real.AlmostEqualNumbersBetween(0, 1) && currentRho.Imaginary.AlmostEqualNumbersBetween(0, 1)) { // Rho-type breakdown throw new NumericalBreakdownException(); } if (iterationNumber != 0) { // beta_(i-1) = (rho_(i-1)/rho_(i-2))(alpha_(i-1)/omega(i-1)) var beta = (currentRho / oldRho) * (alpha / omega); // p_i = r_(i-1) + beta_(i-1)(p_(i-1) - omega_(i-1) * nu_(i-1)) nu.Multiply(-omega, temp); vecP.Add(temp, temp2); temp2.CopyTo(vecP); vecP.Multiply(beta, vecP); vecP.Add(residuals, temp2); temp2.CopyTo(vecP); } else { // p_i = r_(i-1) residuals.CopyTo(vecP); } // SOLVE Mp~ = p_i // M = preconditioner preconditioner.Approximate(vecP, vecPdash); // nu_i = Ap~ matrix.Multiply(vecPdash, nu); // alpha_i = rho_(i-1)/ (r~^T nu_i) = rho / dotproduct(r~ and nu_i) alpha = currentRho * 1 / tempResiduals.ConjugateDotProduct(nu); // s = r_(i-1) - alpha_i nu_i nu.Multiply(-alpha, temp); residuals.Add(temp, vecS); // Check if we're converged. If so then stop. Otherwise continue; // Calculate the temporary result. // Be careful not to change any of the temp vectors, except for // temp. Others will be used in the calculation later on. // x_i = x_(i-1) + alpha_i * p^_i + s^_i vecPdash.Multiply(alpha, temp); temp.Add(vecSdash, temp2); temp2.CopyTo(temp); temp.Add(result, temp2); temp2.CopyTo(temp); // Check convergence and stop if we are converged. if (iterator.DetermineStatus(iterationNumber, temp, input, vecS) != IterationStatus.Continue) { temp.CopyTo(result); // Calculate the true residual CalculateTrueResidual(matrix, residuals, result, input); // Now recheck the convergence if (iterator.DetermineStatus(iterationNumber, result, input, residuals) != IterationStatus.Continue) { // We're all good now. return; } // Continue the calculation iterationNumber++; continue; } // SOLVE Ms~ = s preconditioner.Approximate(vecS, vecSdash); // temp = As~ matrix.Multiply(vecSdash, temp); // omega_i = temp^T s / temp^T temp omega = temp.ConjugateDotProduct(vecS) / temp.ConjugateDotProduct(temp); // x_i = x_(i-1) + alpha_i p^ + omega_i s^ temp.Multiply(-omega, residuals); residuals.Add(vecS, temp2); temp2.CopyTo(residuals); vecSdash.Multiply(omega, temp); result.Add(temp, temp2); temp2.CopyTo(result); vecPdash.Multiply(alpha, temp); result.Add(temp, temp2); temp2.CopyTo(result); // for continuation it is necessary that omega_i != 0.0 // If omega is only 1 ULP from zero then we fail. if (omega.Real.AlmostEqualNumbersBetween(0, 1) && omega.Imaginary.AlmostEqualNumbersBetween(0, 1)) { // Omega-type breakdown throw new NumericalBreakdownException(); } if (iterator.DetermineStatus(iterationNumber, result, input, residuals) != IterationStatus.Continue) { // Recalculate the residuals and go round again. This is done to ensure that // we have the proper residuals. // The residual calculation based on omega_i * s can be off by a factor 10. So here // we calculate the real residual (which can be expensive) but we only do it if we're // sufficiently close to the finish. CalculateTrueResidual(matrix, residuals, result, input); } iterationNumber++; } }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { BCGStabParametrs ConGradParametrs = solverParametrs as BCGStabParametrs; if (ConGradParametrs == null) { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in BSGStab"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in BSGSTab"); } else { int oIter = 0; double nPi, oPi, alpha, w, oNev, bNev, betta; oPi = alpha = w = 1; int size = rightPart.Size; Vector x, r, rTab, s, t, z, sqt, y; Vector v = new Vector(size); Vector p = new Vector(size); v.Nullify(); p.Nullify(); x = initialSolution; r = rightPart - matrix.SourceMatrix.Multiply(x); rTab = r; bNev = rightPart.Norm(); oNev = r.Norm() / bNev; solverLogger.AddIterationInfo(oIter, oNev);//logger if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by BSG Stab."); return(x); } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by BSG Stab."); return(x); } while (oIter < ConGradParametrs.MaxIterations && oNev > ConGradParametrs.Epsilon) { nPi = rTab * r; betta = (nPi / oPi) * (alpha / w); p = r + (p - v * w) * betta; y = matrix.QSolve(matrix.SSolve(p)); v = matrix.SourceMatrix.Multiply(y); alpha = nPi / (rTab * v); x = x + y * alpha;//УТОЧНИТЬ!!!!!!!!!!!!!!! s = r - v * alpha; if (s.Norm() / bNev < ConGradParametrs.Epsilon) { return(x); } z = matrix.QSolve(matrix.SSolve(s)); t = matrix.SourceMatrix.Multiply(z); sqt = matrix.QSolve(matrix.SSolve(t)); w = (z * sqt) / (sqt * sqt); x = x + z * w;//УТОЧНИТЬ!!!!!!!!!!!!!!!!!!! r = s - t * w; oPi = nPi; oIter++; oNev = r.Norm() / bNev; if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by BSG Stab."); return(x); } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by BSG Stab."); return(x); } solverLogger.AddIterationInfo(oIter, oNev);//logger } return(x); } }
/// <summary> /// Solves the matrix equation AX = B, where A is the coefficient matrix (this matrix), B is the solution matrix and X is the unknown matrix. /// </summary> /// <param name="input">The solution matrix <c>B</c>.</param> /// <param name="result">The result matrix <c>X</c></param> /// <param name="solver">The iterative solver to use.</param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public IterationStatus TrySolveIterative(Matrix <T> input, Matrix <T> result, IIterativeSolver <T> solver, Iterator <T> iterator = null, IPreconditioner <T> preconditioner = null) { if (RowCount != input.RowCount || input.RowCount != result.RowCount || input.ColumnCount != result.ColumnCount) { throw DimensionsDontMatch <ArgumentException>(this, input, result); } if (iterator == null) { iterator = new Iterator <T>(Build.IterativeSolverStopCriteria()); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <T>(); } for (var column = 0; column < input.ColumnCount; column++) { var solution = Vector <T> .Build.Dense(RowCount); solver.Solve(this, input.Column(column), solution, iterator, preconditioner); foreach (var element in solution.EnumerateIndexed(Zeros.AllowSkip)) { result.At(element.Item1, column, element.Item2); } } return(iterator.Status); }
public abstract Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger,ISolverLogger solverLogger, ISolverParametrs solverParametrs);
// Iterative Solvers: Simple /// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix (this matrix), b is the solution vector and x is the unknown vector. /// </summary> /// <param name="input">The solution vector <c>b</c>.</param> /// <param name="solver">The iterative solver to use.</param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> /// <returns>The result vector <c>x</c>.</returns> public Vector <T> SolveIterative(Vector <T> input, IIterativeSolver <T> solver, Iterator <T> iterator = null, IPreconditioner <T> preconditioner = null) { var result = Vector <T> .Build.Dense(RowCount); TrySolveIterative(input, result, solver, iterator, preconditioner); return(result); }
public IterativeStatistics Solve(IMatrixView matrix, IPreconditioner preconditioner, IVectorView rhs, IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer) { return(Solve(new ExplicitMatrixTransformation(matrix), preconditioner, rhs, solution, initialGuessIsZero, zeroVectorInitializer)); }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix (this matrix), b is the solution vector and x is the unknown vector. /// </summary> /// <param name="input">The solution vector <c>b</c>.</param> /// <param name="solver">The iterative solver to use.</param> /// <param name="stopCriteria">Criteria to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> /// <returns>The result vector <c>x</c>.</returns> public Vector <T> SolveIterative(Vector <T> input, IIterativeSolver <T> solver, IPreconditioner <T> preconditioner, params IIterationStopCriterion <T>[] stopCriteria) { var result = Vector <T> .Build.Dense(RowCount); TrySolveIterative(input, result, solver, preconditioner, stopCriteria); return(result); }
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 }); }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient matrix, <c>A</c>.</param> /// <param name="input">The solution vector, <c>b</c></param> /// <param name="result">The result vector, <c>x</c></param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public void Solve(Matrix <Numerics.Complex32> matrix, Vector <Numerics.Complex32> input, Vector <Numerics.Complex32> result, Iterator <Numerics.Complex32> iterator, IPreconditioner <Numerics.Complex32> preconditioner) { if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix"); } if (result.Count != input.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (input.Count != matrix.RowCount) { throw Matrix.DimensionsDontMatch <ArgumentException>(input, matrix); } if (iterator == null) { iterator = new Iterator <Numerics.Complex32>(); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <Numerics.Complex32>(); } preconditioner.Initialize(matrix); // Choose an initial guess x_0 // Take x_0 = 0 var xtemp = new DenseVector(input.Count); // Choose k vectors q_1, q_2, ..., q_k // Build a new set if: // a) the stored set doesn't exist (i.e. == null) // b) Is of an incorrect length (i.e. too long) // c) The vectors are of an incorrect length (i.e. too long or too short) var useOld = false; if (_startingVectors != null) { // We don't accept collections with zero starting vectors so ... if (_startingVectors.Count <= NumberOfStartingVectorsToCreate(_numberOfStartingVectors, input.Count)) { // Only check the first vector for sizing. If that matches we assume the // other vectors match too. If they don't the process will crash if (_startingVectors[0].Count == input.Count) { useOld = true; } } } _startingVectors = useOld ? _startingVectors : CreateStartingVectors(_numberOfStartingVectors, input.Count); // Store the number of starting vectors. Not really necessary but easier to type :) var k = _startingVectors.Count; // r_0 = b - Ax_0 // This is basically a SAXPY so it could be made a lot faster var residuals = new DenseVector(matrix.RowCount); CalculateTrueResidual(matrix, residuals, xtemp, input); // Define the temporary values var c = new Numerics.Complex32[k]; // Define the temporary vectors var gtemp = new DenseVector(residuals.Count); var u = new DenseVector(residuals.Count); var utemp = new DenseVector(residuals.Count); var temp = new DenseVector(residuals.Count); var temp1 = new DenseVector(residuals.Count); var temp2 = new DenseVector(residuals.Count); var zd = new DenseVector(residuals.Count); var zg = new DenseVector(residuals.Count); var zw = new DenseVector(residuals.Count); var d = CreateVectorArray(_startingVectors.Count, residuals.Count); // g_0 = r_0 var g = CreateVectorArray(_startingVectors.Count, residuals.Count); residuals.CopyTo(g[k - 1]); var w = CreateVectorArray(_startingVectors.Count, residuals.Count); // FOR (j = 0, 1, 2 ....) var iterationNumber = 0; while (iterator.DetermineStatus(iterationNumber, xtemp, input, residuals) == IterationStatus.Continue) { // SOLVE M g~_((j-1)k+k) = g_((j-1)k+k) preconditioner.Approximate(g[k - 1], gtemp); // w_((j-1)k+k) = A g~_((j-1)k+k) matrix.Multiply(gtemp, w[k - 1]); // c_((j-1)k+k) = q^T_1 w_((j-1)k+k) c[k - 1] = _startingVectors[0].ConjugateDotProduct(w[k - 1]); if (c[k - 1].Real.AlmostEqualNumbersBetween(0, 1) && c[k - 1].Imaginary.AlmostEqualNumbersBetween(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // alpha_(jk+1) = q^T_1 r_((j-1)k+k) / c_((j-1)k+k) var alpha = _startingVectors[0].ConjugateDotProduct(residuals) / c[k - 1]; // u_(jk+1) = r_((j-1)k+k) - alpha_(jk+1) w_((j-1)k+k) w[k - 1].Multiply(-alpha, temp); residuals.Add(temp, u); // SOLVE M u~_(jk+1) = u_(jk+1) preconditioner.Approximate(u, temp1); temp1.CopyTo(utemp); // rho_(j+1) = -u^t_(jk+1) A u~_(jk+1) / ||A u~_(jk+1)||^2 matrix.Multiply(temp1, temp); var rho = temp.ConjugateDotProduct(temp); // If rho is zero then temp is a zero vector and we're probably // about to have zero residuals (i.e. an exact solution). // So set rho to 1.0 because in the next step it will turn to zero. if (rho.Real.AlmostEqualNumbersBetween(0, 1) && rho.Imaginary.AlmostEqualNumbersBetween(0, 1)) { rho = 1.0f; } rho = -u.ConjugateDotProduct(temp) / rho; // r_(jk+1) = rho_(j+1) A u~_(jk+1) + u_(jk+1) u.CopyTo(residuals); // Reuse temp temp.Multiply(rho, temp); residuals.Add(temp, temp2); temp2.CopyTo(residuals); // x_(jk+1) = x_((j-1)k_k) - rho_(j+1) u~_(jk+1) + alpha_(jk+1) g~_((j-1)k+k) utemp.Multiply(-rho, temp); xtemp.Add(temp, temp2); temp2.CopyTo(xtemp); gtemp.Multiply(alpha, gtemp); xtemp.Add(gtemp, temp2); temp2.CopyTo(xtemp); // Check convergence and stop if we are converged. if (iterator.DetermineStatus(iterationNumber, xtemp, input, residuals) != IterationStatus.Continue) { // Calculate the true residual CalculateTrueResidual(matrix, residuals, xtemp, input); // Now recheck the convergence if (iterator.DetermineStatus(iterationNumber, xtemp, input, residuals) != IterationStatus.Continue) { // We're all good now. // Exit from the while loop. break; } } // FOR (i = 1,2, ...., k) for (var i = 0; i < k; i++) { // z_d = u_(jk+1) u.CopyTo(zd); // z_g = r_(jk+i) residuals.CopyTo(zg); // z_w = 0 zw.Clear(); // FOR (s = i, ...., k-1) AND j >= 1 Numerics.Complex32 beta; if (iterationNumber >= 1) { for (var s = i; s < k - 1; s++) { // beta^(jk+i)_((j-1)k+s) = -q^t_(s+1) z_d / c_((j-1)k+s) beta = -_startingVectors[s + 1].ConjugateDotProduct(zd) / c[s]; // z_d = z_d + beta^(jk+i)_((j-1)k+s) d_((j-1)k+s) d[s].Multiply(beta, temp); zd.Add(temp, temp2); temp2.CopyTo(zd); // z_g = z_g + beta^(jk+i)_((j-1)k+s) g_((j-1)k+s) g[s].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); // z_w = z_w + beta^(jk+i)_((j-1)k+s) w_((j-1)k+s) w[s].Multiply(beta, temp); zw.Add(temp, temp2); temp2.CopyTo(zw); } } beta = rho * c[k - 1]; if (beta.Real.AlmostEqualNumbersBetween(0, 1) && beta.Imaginary.AlmostEqualNumbersBetween(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // beta^(jk+i)_((j-1)k+k) = -(q^T_1 (r_(jk+1) + rho_(j+1) z_w)) / (rho_(j+1) c_((j-1)k+k)) zw.Multiply(rho, temp2); residuals.Add(temp2, temp); beta = -_startingVectors[0].ConjugateDotProduct(temp) / beta; // z_g = z_g + beta^(jk+i)_((j-1)k+k) g_((j-1)k+k) g[k - 1].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); // z_w = rho_(j+1) (z_w + beta^(jk+i)_((j-1)k+k) w_((j-1)k+k)) w[k - 1].Multiply(beta, temp); zw.Add(temp, temp2); temp2.CopyTo(zw); zw.Multiply(rho, zw); // z_d = r_(jk+i) + z_w residuals.Add(zw, zd); // FOR (s = 1, ... i - 1) for (var s = 0; s < i - 1; s++) { // beta^(jk+i)_(jk+s) = -q^T_s+1 z_d / c_(jk+s) beta = -_startingVectors[s + 1].ConjugateDotProduct(zd) / c[s]; // z_d = z_d + beta^(jk+i)_(jk+s) * d_(jk+s) d[s].Multiply(beta, temp); zd.Add(temp, temp2); temp2.CopyTo(zd); // z_g = z_g + beta^(jk+i)_(jk+s) * g_(jk+s) g[s].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); } // d_(jk+i) = z_d - u_(jk+i) zd.Subtract(u, d[i]); // g_(jk+i) = z_g + z_w zg.Add(zw, g[i]); // IF (i < k - 1) if (i < k - 1) { // c_(jk+1) = q^T_i+1 d_(jk+i) c[i] = _startingVectors[i + 1].ConjugateDotProduct(d[i]); if (c[i].Real.AlmostEqualNumbersBetween(0, 1) && c[i].Imaginary.AlmostEqualNumbersBetween(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // alpha_(jk+i+1) = q^T_(i+1) u_(jk+i) / c_(jk+i) alpha = _startingVectors[i + 1].ConjugateDotProduct(u) / c[i]; // u_(jk+i+1) = u_(jk+i) - alpha_(jk+i+1) d_(jk+i) d[i].Multiply(-alpha, temp); u.Add(temp, temp2); temp2.CopyTo(u); // SOLVE M g~_(jk+i) = g_(jk+i) preconditioner.Approximate(g[i], gtemp); // x_(jk+i+1) = x_(jk+i) + rho_(j+1) alpha_(jk+i+1) g~_(jk+i) gtemp.Multiply(rho * alpha, temp); xtemp.Add(temp, temp2); temp2.CopyTo(xtemp); // w_(jk+i) = A g~_(jk+i) matrix.Multiply(gtemp, w[i]); // r_(jk+i+1) = r_(jk+i) - rho_(j+1) alpha_(jk+i+1) w_(jk+i) w[i].Multiply(-rho * alpha, temp); residuals.Add(temp, temp2); temp2.CopyTo(residuals); // We can check the residuals here if they're close if (iterator.DetermineStatus(iterationNumber, xtemp, input, residuals) != IterationStatus.Continue) { // Recalculate the residuals and go round again. This is done to ensure that // we have the proper residuals. CalculateTrueResidual(matrix, residuals, xtemp, input); } } } // END ITERATION OVER i iterationNumber++; } // copy the temporary result to the real result vector xtemp.CopyTo(result); }
/// <summary> Sets left preconditioner</summary> public virtual void setM1(IPreconditioner preconditioner) { M1 = preconditioner; }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient matrix, <c>A</c>.</param> /// <param name="input">The solution vector, <c>b</c></param> /// <param name="result">The result vector, <c>x</c></param> /// <param name="iterator">The iterator to use to control when to stop iterating.</param> /// <param name="preconditioner">The preconditioner to use for approximations.</param> public void Solve(Matrix <double> matrix, Vector <double> input, Vector <double> result, Iterator <double> iterator, IPreconditioner <double> preconditioner) { if (matrix.RowCount != matrix.ColumnCount) { throw new ArgumentException(Resources.ArgumentMatrixSquare, nameof(matrix)); } if (result.Count != input.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (input.Count != matrix.RowCount) { throw Matrix.DimensionsDontMatch <ArgumentException>(input, matrix); } if (iterator == null) { iterator = new Iterator <double>(); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <double>(); } preconditioner.Initialize(matrix); // x_0 is initial guess // Take x_0 = 0 var xtemp = new DenseVector(input.Count); // r_0 = b - Ax_0 // This is basically a SAXPY so it could be made a lot faster var residuals = new DenseVector(matrix.RowCount); CalculateTrueResidual(matrix, residuals, xtemp, input); // Define the temporary scalars double beta = 0; // Define the temporary vectors // rDash_0 = r_0 var rdash = DenseVector.OfVector(residuals); // t_-1 = 0 var t = new DenseVector(residuals.Count); var t0 = new DenseVector(residuals.Count); // w_-1 = 0 var w = new DenseVector(residuals.Count); // Define the remaining temporary vectors var c = new DenseVector(residuals.Count); var p = new DenseVector(residuals.Count); var s = new DenseVector(residuals.Count); var u = new DenseVector(residuals.Count); var y = new DenseVector(residuals.Count); var z = new DenseVector(residuals.Count); var temp = new DenseVector(residuals.Count); var temp2 = new DenseVector(residuals.Count); var temp3 = new DenseVector(residuals.Count); // for (k = 0, 1, .... ) var iterationNumber = 0; while (iterator.DetermineStatus(iterationNumber, xtemp, input, residuals) == IterationStatus.Continue) { // p_k = r_k + beta_(k-1) * (p_(k-1) - u_(k-1)) p.Subtract(u, temp); temp.Multiply(beta, temp2); residuals.Add(temp2, p); // Solve M b_k = p_k preconditioner.Approximate(p, temp); // s_k = A b_k matrix.Multiply(temp, s); // alpha_k = (r*_0 * r_k) / (r*_0 * s_k) var alpha = rdash.DotProduct(residuals) / rdash.DotProduct(s); // y_k = t_(k-1) - r_k - alpha_k * w_(k-1) + alpha_k s_k s.Subtract(w, temp); t.Subtract(residuals, y); temp.Multiply(alpha, temp2); y.Add(temp2, temp3); temp3.CopyTo(y); // Store the old value of t in t0 t.CopyTo(t0); // t_k = r_k - alpha_k s_k s.Multiply(-alpha, temp2); residuals.Add(temp2, t); // Solve M d_k = t_k preconditioner.Approximate(t, temp); // c_k = A d_k matrix.Multiply(temp, c); var cdot = c.DotProduct(c); // cDot can only be zero if c is a zero vector // We'll set cDot to 1 if it is zero to prevent NaN's // Note that the calculation should continue fine because // c.DotProduct(t) will be zero and so will c.DotProduct(y) if (cdot.AlmostEqualNumbersBetween(0, 1)) { cdot = 1.0; } // Even if we don't want to do any BiCGStab steps we'll still have // to do at least one at the start to initialize the // system, but we'll only have to take special measures // if we don't do any so ... var ctdot = c.DotProduct(t); double eta; double sigma; if (((_numberOfBiCgStabSteps == 0) && (iterationNumber == 0)) || ShouldRunBiCgStabSteps(iterationNumber)) { // sigma_k = (c_k * t_k) / (c_k * c_k) sigma = ctdot / cdot; // eta_k = 0 eta = 0; } else { var ydot = y.DotProduct(y); // yDot can only be zero if y is a zero vector // We'll set yDot to 1 if it is zero to prevent NaN's // Note that the calculation should continue fine because // y.DotProduct(t) will be zero and so will c.DotProduct(y) if (ydot.AlmostEqualNumbersBetween(0, 1)) { ydot = 1.0; } var ytdot = y.DotProduct(t); var cydot = c.DotProduct(y); var denom = (cdot * ydot) - (cydot * cydot); // sigma_k = ((y_k * y_k)(c_k * t_k) - (y_k * t_k)(c_k * y_k)) / ((c_k * c_k)(y_k * y_k) - (y_k * c_k)(c_k * y_k)) sigma = ((ydot * ctdot) - (ytdot * cydot)) / denom; // eta_k = ((c_k * c_k)(y_k * t_k) - (y_k * c_k)(c_k * t_k)) / ((c_k * c_k)(y_k * y_k) - (y_k * c_k)(c_k * y_k)) eta = ((cdot * ytdot) - (cydot * ctdot)) / denom; } // u_k = sigma_k s_k + eta_k (t_(k-1) - r_k + beta_(k-1) u_(k-1)) u.Multiply(beta, temp2); t0.Add(temp2, temp); temp.Subtract(residuals, temp3); temp3.CopyTo(temp); temp.Multiply(eta, temp); s.Multiply(sigma, temp2); temp.Add(temp2, u); // z_k = sigma_k r_k +_ eta_k z_(k-1) - alpha_k u_k z.Multiply(eta, z); u.Multiply(-alpha, temp2); z.Add(temp2, temp3); temp3.CopyTo(z); residuals.Multiply(sigma, temp2); z.Add(temp2, temp3); temp3.CopyTo(z); // x_(k+1) = x_k + alpha_k p_k + z_k p.Multiply(alpha, temp2); xtemp.Add(temp2, temp3); temp3.CopyTo(xtemp); xtemp.Add(z, temp3); temp3.CopyTo(xtemp); // r_(k+1) = t_k - eta_k y_k - sigma_k c_k // Copy the old residuals to a temp vector because we'll // need those in the next step residuals.CopyTo(t0); y.Multiply(-eta, temp2); t.Add(temp2, residuals); c.Multiply(-sigma, temp2); residuals.Add(temp2, temp3); temp3.CopyTo(residuals); // beta_k = alpha_k / sigma_k * (r*_0 * r_(k+1)) / (r*_0 * r_k) // But first we check if there is a possible NaN. If so just reset beta to zero. beta = (!sigma.AlmostEqualNumbersBetween(0, 1)) ? alpha / sigma * rdash.DotProduct(residuals) / rdash.DotProduct(t0) : 0; // w_k = c_k + beta_k s_k s.Multiply(beta, temp2); c.Add(temp2, w); // Get the real value preconditioner.Approximate(xtemp, result); // Now check for convergence if (iterator.DetermineStatus(iterationNumber, result, input, residuals) != IterationStatus.Continue) { // Recalculate the residuals and go round again. This is done to ensure that // we have the proper residuals. CalculateTrueResidual(matrix, residuals, result, input); } // Next iteration. iterationNumber++; } }
/// <summary> Sets right preconditioner</summary> public virtual void setM2(IPreconditioner preconditioner) { M2 = preconditioner; }
/// <summary> /// Check the result. /// </summary> /// <param name="preconditioner">Specific preconditioner.</param> /// <param name="matrix">Source matrix.</param> /// <param name="vector">Initial vector.</param> /// <param name="result">Result vector.</param> protected abstract void CheckResult(IPreconditioner<Complex> preconditioner, SparseMatrix matrix, Vector<Complex> vector, Vector<Complex> result);
public QMRSolver() : base() { M1 = M; M2 = M; }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { MSGParametrs ConGradParametrs = solverParametrs as MSGParametrs; if (ConGradParametrs == null) { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in MSG"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in MSG"); } else { //prestart int oIter = 0; double alpha, beta, oNev, bNev, scalRO, scaleRN; Vector x = initialSolution, rNew, rOld, z, ap, p; rOld = rightPart - matrix.SourceMatrix.Multiply(x); z = matrix.QSolve(matrix.SSolve(rOld)); p = z; ap = matrix.SourceMatrix.Multiply(p); bNev = rightPart.Norm(); oNev = rOld.Norm() / bNev; scalRO = z * rOld; // x = matrix.QSolve(x); solverLogger.AddIterationInfo(oIter, oNev);//logger if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by MSG."); return x; } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by MSG."); return x; } while (oIter < ConGradParametrs.MaxIterations && oNev > ConGradParametrs.Epsilon) { alpha = scalRO / (ap * p); x = x + p * alpha; //if (oIter % 100 == 0) //rNew = matrix.QMultiply(rightPart - matrix.SMultiply(matrix.SourceMatrix.Multiply(x))); //else rNew = rOld - ap * alpha; z = matrix.QSolve(matrix.SSolve(rNew)); scaleRN = z * rNew; beta = scaleRN / scalRO; scalRO = scaleRN; p = z + p * beta; ap = matrix.SourceMatrix.Multiply(p); rOld = rNew; oIter++; oNev = rNew.Norm() / bNev; if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by MSG."); return x; } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by MSG."); return x; } solverLogger.AddIterationInfo(oIter, oNev);//logger } return x; } }
public override Vector Solve(IPreconditioner matrix, Vector rightPart, Vector initialSolution, ILogger logger, ISolverLogger solverLogger, ISolverParametrs solverParametrs) { MSGParametrs ConGradParametrs = solverParametrs as MSGParametrs; if (ConGradParametrs == null) { logger.Error("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in MSG"); throw new Exception("Incorrect " + solverParametrs.GetType().Name.ToString() + " as a SolverParametrs in MSG"); } else { //prestart int oIter = 0; double alpha, beta, oNev, bNev, scalRO, scaleRN; Vector x = initialSolution, rNew, rOld, z, ap, p; rOld = rightPart - matrix.SourceMatrix.Multiply(x); z = matrix.QSolve(matrix.SSolve(rOld)); p = z; ap = matrix.SourceMatrix.Multiply(p); bNev = rightPart.Norm(); oNev = rOld.Norm() / bNev; scalRO = z * rOld; // x = matrix.QSolve(x); solverLogger.AddIterationInfo(oIter, oNev);//logger if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by MSG."); return(x); } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by MSG."); return(x); } while (oIter < ConGradParametrs.MaxIterations && oNev > ConGradParametrs.Epsilon) { alpha = scalRO / (ap * p); x = x + p * alpha; //if (oIter % 100 == 0) //rNew = matrix.QMultiply(rightPart - matrix.SMultiply(matrix.SourceMatrix.Multiply(x))); //else rNew = rOld - ap * alpha; z = matrix.QSolve(matrix.SSolve(rNew)); scaleRN = z * rNew; beta = scaleRN / scalRO; scalRO = scaleRN; p = z + p * beta; ap = matrix.SourceMatrix.Multiply(p); rOld = rNew; oIter++; oNev = rNew.Norm() / bNev; if (System.Double.IsInfinity(oNev)) { logger.Error("Residual is infinity. It is impossible to solve this SLAE by MSG."); return(x); } if (System.Double.IsNaN(oNev)) { logger.Error("Residual is NaN. It is impossible to solve this SLAE by MSG."); return(x); } solverLogger.AddIterationInfo(oIter, oNev);//logger } return(x); } }