public void DetermineStatus() { var criteria = new List<IIterationStopCriterium<Complex32>> { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium<Complex32>(1) }; var iterator = new Iterator<Complex32>(criteria); // First step, nothing should happen. iterator.DetermineStatus( 0, DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 4)); Assert.AreEqual(IterationStatus.Continue, iterator.Status, "Incorrect status"); // Second step, should run out of iterations. iterator.DetermineStatus( 1, DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 4)); Assert.AreEqual(IterationStatus.StoppedWithoutConvergence, iterator.Status, "Incorrect status"); }
/// <summary> /// Creates a default iterator with all the <see cref="IIterationStopCriterium"/> objects. /// </summary> /// <returns>A new <see cref="IIterator"/> object.</returns> public static IIterator CreateDefault() { var iterator = new Iterator(); iterator.Add(new FailureStopCriterium()); iterator.Add(new DivergenceStopCriterium()); iterator.Add(new IterationCountStopCriterium()); iterator.Add(new ResidualStopCriterium()); return iterator; }
public void CanSolveForRandomMatrix(int order) { for (var iteration = 5; iteration > 3; iteration--) { var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); var monitor = new Iterator<Complex32>(new IIterationStopCriterium<Complex32>[] { new IterationCountStopCriterium<Complex32>(1000), new ResidualStopCriterium((float) Math.Pow(1.0/10.0, iteration)) }); var solver = new TFQMR(monitor); var matrixX = solver.Solve(matrixA, matrixB); if (!monitor.HasConverged) { // Solution was not found, try again downgrading convergence boundary continue; } // The solution X row dimension is equal to the column dimension of A Assert.AreEqual(matrixA.ColumnCount, matrixX.RowCount); // The solution X has the same number of columns as B Assert.AreEqual(matrixB.ColumnCount, matrixX.ColumnCount); var matrixBReconstruct = matrixA*matrixX; // Check the reconstruction. for (var i = 0; i < matrixB.RowCount; i++) { for (var j = 0; j < matrixB.ColumnCount; j++) { Assert.AreEqual(matrixB[i, j].Real, matrixBReconstruct[i, j].Real, (float) Math.Pow(1.0/10.0, iteration - 3)); Assert.AreEqual(matrixB[i, j].Imaginary, matrixBReconstruct[i, j].Imaginary, (float) Math.Pow(1.0/10.0, iteration - 3)); } } return; } Assert.Fail("Solution was not found in 3 tries"); }
public void CanSolveForRandomVector(int order) { for (var iteration = 5; iteration > 3; iteration--) { var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); var vectorb = MatrixLoader.GenerateRandomDenseVector(order); var monitor = new Iterator<Complex32>(new IIterationStopCriterium<Complex32>[] { new IterationCountStopCriterium<Complex32>(1000), new ResidualStopCriterium((float) Math.Pow(1.0/10.0, iteration)), }); var solver = new GpBiCg(monitor); var resultx = solver.Solve(matrixA, vectorb); if (!monitor.HasConverged) { // Solution was not found, try again downgrading convergence boundary continue; } Assert.AreEqual(matrixA.ColumnCount, resultx.Count); var matrixBReconstruct = matrixA*resultx; // Check the reconstruction. for (var i = 0; i < order; i++) { Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, (float) Math.Pow(1.0/10.0, iteration - 3)); Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, (float) Math.Pow(1.0/10.0, iteration - 3)); } return; } Assert.Fail("Solution was not found in 3 tries"); }
public void CanSolveForRandomVector(int order) { for (var iteration = 5; iteration > 3; iteration--) { var matrixA = Matrix<Complex32>.Build.Random(order, order, 1); var vectorb = Vector<Complex32>.Build.Random(order, 1); var monitor = new Iterator<Complex32>( new IterationCountStopCriterium<Complex32>(1000), new ResidualStopCriterium<Complex32>(Math.Pow(1.0 / 10.0, iteration))); var solver = new GpBiCg(); var resultx = matrixA.SolveIterative(vectorb, solver, monitor); if (monitor.Status != IterationStatus.Converged) { // Solution was not found, try again downgrading convergence boundary continue; } Assert.AreEqual(matrixA.ColumnCount, resultx.Count); var matrixBReconstruct = matrixA*resultx; // Check the reconstruction. for (var i = 0; i < order; i++) { Assert.AreEqual(vectorb[i].Real, matrixBReconstruct[i].Real, (float) Math.Pow(1.0/10.0, iteration - 3)); Assert.AreEqual(vectorb[i].Imaginary, matrixBReconstruct[i].Imaginary, (float) Math.Pow(1.0/10.0, iteration - 3)); } return; } Assert.Fail("Solution was not found in 3 tries"); }
public void SolveUnitMatrixAndBackMultiply() { // Create the identity matrix var matrix = SparseMatrix.Identity(100); // Create the y vector var y = DenseVector.Create(matrix.RowCount, i => 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<Complex32>(new IIterationStopCriterium<Complex32>[] { new IterationCountStopCriterium<Complex32>(MaximumIterations), new ResidualStopCriterium(ConvergenceBoundary), new DivergenceStopCriterium(), new FailureStopCriterium() }); var solver = new TFQMR(monitor); // Solve equation Ax = y var x = solver.Solve(matrix, y); // Now compare the results Assert.IsNotNull(x, "#02"); Assert.AreEqual(y.Count, x.Count, "#03"); // Back multiply the vector var z = matrix.Multiply(x); // Check that the solution converged Assert.IsTrue(monitor.HasConverged, "#04"); // Now compare the vectors for (var i = 0; i < y.Count; i++) { Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(ConvergenceBoundary, 1), "#05-" + i); } }
public void SolvePoissonMatrixAndBackMultiply() { // Create the matrix var matrix = new SparseMatrix(25); // Assemble the matrix. We assume we're solving the Poisson equation // on a rectangular 5 x 5 grid const int GridSize = 5; // The pattern is: // 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0 for (var i = 0; i < matrix.RowCount; i++) { // Insert the first set of -1's if (i > (GridSize - 1)) { matrix[i, i - GridSize] = -1; } // Insert the second set of -1's if (i > 0) { matrix[i, i - 1] = -1; } // Insert the centerline values matrix[i, i] = 4; // Insert the first trailing set of -1's if (i < matrix.RowCount - 1) { matrix[i, i + 1] = -1; } // Insert the second trailing set of -1's if (i < matrix.RowCount - GridSize) { matrix[i, i + GridSize] = -1; } } // Create the y vector var y = DenseVector.Create(matrix.RowCount, i => 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<Complex32>(new IIterationStopCriterium<Complex32>[] { new IterationCountStopCriterium<Complex32>(MaximumIterations), new ResidualStopCriterium(ConvergenceBoundary), new DivergenceStopCriterium(), new FailureStopCriterium() }); var solver = new TFQMR(monitor); // Solve equation Ax = y var x = solver.Solve(matrix, y); // Now compare the results Assert.IsNotNull(x, "#02"); Assert.AreEqual(y.Count, x.Count, "#03"); // Back multiply the vector var z = matrix.Multiply(x); // Check that the solution converged Assert.IsTrue(monitor.HasConverged, "#04"); // Now compare the vectors for (var i = 0; i < y.Count; i++) { Assert.IsTrue((y[i] - z[i]).Magnitude.IsSmaller(1e-4f, 1), "#05-" + i); } }
public void SolveUnitMatrixAndBackMultiply() { // Create the identity matrix var matrix = SparseMatrix.CreateIdentity(100); // Create the y vector var y = DenseVector.Create(matrix.RowCount, i => Complex32.One); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<Complex32>( new IterationCountStopCriterium<Complex32>(MaximumIterations), new ResidualStopCriterium<Complex32>(ConvergenceBoundary), new DivergenceStopCriterium<Complex32>(), new FailureStopCriterium<Complex32>()); var solver = new BiCgStab(); // Solve equation Ax = y var x = matrix.SolveIterative(y, solver, monitor); // Now compare the results Assert.IsNotNull(x, "#02"); Assert.AreEqual(y.Count, x.Count, "#03"); // Back multiply the vector var z = matrix.Multiply(x); // Check that the solution converged Assert.IsTrue(monitor.Status == IterationStatus.Converged, "#04"); // Now compare the vectors for (var i = 0; i < y.Count; i++) { Assert.GreaterOrEqual(ConvergenceBoundary, (y[i] - z[i]).Magnitude, "#05-" + i); } }
public void DetermineStatusWithNegativeIterationNumberThrowsArgumentOutOfRangeException() { var criteria = new List<IIterationStopCriterium<Complex32>> { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium<Complex32>(), new ResidualStopCriterium() }; var iterator = new Iterator<Complex32>(criteria); Assert.Throws<ArgumentOutOfRangeException>(() => iterator.DetermineStatus( -1, DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 5), DenseVector.Create(3, i => 6))); }
public void ResetToPrecalculationState() { var criteria = new List<IIterationStopCriterium<Complex32>> { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium<Complex32>(1) }; var iterator = new Iterator<Complex32>(criteria); // First step, nothing should happen. iterator.DetermineStatus( 0, DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 4)); Assert.AreEqual(IterationStatus.Continue, iterator.Status, "Incorrect status"); iterator.Reset(); Assert.AreEqual(IterationStatus.Continue, iterator.Status, "Incorrect status"); Assert.AreEqual(IterationStatus.Continue, criteria[0].Status, "Incorrect status"); Assert.AreEqual(IterationStatus.Continue, criteria[1].Status, "Incorrect status"); Assert.AreEqual(IterationStatus.Continue, criteria[2].Status, "Incorrect status"); }
public void DetermineStatusWithoutStopCriteriaDoesNotThrow() { var iterator = new Iterator<Complex32>(); Assert.DoesNotThrow(() => iterator.DetermineStatus( 0, DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 5), DenseVector.Create(3, i => 6))); }
public void SolveUnitMatrixAndBackMultiply() { // Create the identity matrix var matrix = SparseMatrix.CreateIdentity(100); // Create the y vector var y = Vector<Complex32>.Build.Dense(matrix.RowCount, 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<Complex32>( new IterationCountStopCriterium<Complex32>(MaximumIterations), new ResidualStopCriterium<Complex32>(ConvergenceBoundary), new DivergenceStopCriterium<Complex32>(), new FailureStopCriterium<Complex32>()); var solver = new TFQMR(); // Solve equation Ax = y var x = matrix.SolveIterative(y, solver, monitor); // Now compare the results Assert.IsNotNull(x, "#02"); Assert.AreEqual(y.Count, x.Count, "#03"); // Back multiply the vector var z = matrix.Multiply(x); // Check that the solution converged Assert.IsTrue(monitor.Status == IterationStatus.Converged, "#04"); // Now compare the vectors Assert.LessOrEqual(Distance.Chebyshev(y, z), 2*ConvergenceBoundary); }
public void SolvePoissonMatrixAndBackMultiply() { // Create the matrix var matrix = new SparseMatrix(25); // Assemble the matrix. We assume we're solving the Poisson equation // on a rectangular 5 x 5 grid const int GridSize = 5; // The pattern is: // 0 .... 0 -1 0 0 0 0 0 0 0 0 -1 4 -1 0 0 0 0 0 0 0 0 -1 0 0 ... 0 for (var i = 0; i < matrix.RowCount; i++) { // Insert the first set of -1's if (i > (GridSize - 1)) { matrix[i, i - GridSize] = -1; } // Insert the second set of -1's if (i > 0) { matrix[i, i - 1] = -1; } // Insert the centerline values matrix[i, i] = 4; // Insert the first trailing set of -1's if (i < matrix.RowCount - 1) { matrix[i, i + 1] = -1; } // Insert the second trailing set of -1's if (i < matrix.RowCount - GridSize) { matrix[i, i + GridSize] = -1; } } // Create the y vector var y = Vector<Complex32>.Build.Dense(matrix.RowCount, 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<Complex32>( new IterationCountStopCriterium<Complex32>(MaximumIterations), new ResidualStopCriterium<Complex32>(ConvergenceBoundary), new DivergenceStopCriterium<Complex32>(), new FailureStopCriterium<Complex32>()); var solver = new TFQMR(); // Solve equation Ax = y var x = matrix.SolveIterative(y, solver, monitor); // Now compare the results Assert.IsNotNull(x, "#02"); Assert.AreEqual(y.Count, x.Count, "#03"); // Back multiply the vector var z = matrix.Multiply(x); // Check that the solution converged Assert.IsTrue(monitor.Status == IterationStatus.Converged, "#04"); // Now compare the vectors Assert.LessOrEqual(Distance.Chebyshev(y, z), 2*ConvergenceBoundary); }
/// <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); // 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 Numerics.Complex32 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.ConjugateDotProduct(residuals) / rdash.ConjugateDotProduct(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.ConjugateDotProduct(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.Real.AlmostEqualNumbersBetween(0, 1) && cdot.Imaginary.AlmostEqualNumbersBetween(0, 1)) { cdot = 1.0f; } // 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.ConjugateDotProduct(t); Numerics.Complex32 eta; Numerics.Complex32 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.ConjugateDotProduct(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.Real.AlmostEqualNumbersBetween(0, 1) && ydot.Imaginary.AlmostEqualNumbersBetween(0, 1)) { ydot = 1.0f; } var ytdot = y.ConjugateDotProduct(t); var cydot = c.ConjugateDotProduct(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.Real.AlmostEqualNumbersBetween(0, 1) || !sigma.Imaginary.AlmostEqualNumbersBetween(0, 1)) ? alpha / sigma * rdash.ConjugateDotProduct(residuals) / rdash.ConjugateDotProduct(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> /// 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 NumericalBreakdownException(); } // 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 NumericalBreakdownException(); } // 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 NumericalBreakdownException(); } // 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); }