public void DetermineStatus() { var criteria = new List<IIterationStopCriterium<double>> { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium<double>(1) }; var iterator = new Iterator<double>(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"); }
public void CanSolveForRandomMatrix(int order) { var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); var matrixB = MatrixLoader.GenerateRandomDenseMatrix(order, order); var monitor = new Iterator<double>(new IIterationStopCriterium<double>[] { new IterationCountStopCriterium<double>(1000), new ResidualStopCriterium(1e-10) }); var solver = new TFQMR(monitor); var matrixX = solver.Solve(matrixA, matrixB); // 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], matrixBReconstruct[i, j], 1.0e-7); } } }
public void CanSolveForRandomMatrix(int order) { var matrixA = Matrix<double>.Build.Random(order, order, 1); var matrixB = Matrix<double>.Build.Random(order, order, 1); var monitor = new Iterator<double>( new IterationCountStopCriterium<double>(1000), new ResidualStopCriterium<double>(1e-10)); var solver = new GpBiCg(); var matrixX = matrixA.SolveIterative(matrixB, solver, monitor); // 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], matrixBReconstruct[i, j], 1.0e-7); } } }
/// <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 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<double>(new IIterationStopCriterium<double>[] { new IterationCountStopCriterium<double>(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]).IsSmaller(ConvergenceBoundary, 1), "#05-" + i); } }
public void ResetToPrecalculationState() { var criteria = new List<IIterationStopCriterium<double>> { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium<double>(1) }; var iterator = new Iterator<double>(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<double>(); 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 = Matrix<double>.Build.SparseIdentity(100); // Create the y vector var y = Vector<double>.Build.Dense(matrix.RowCount, 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<double>( new IterationCountStopCriterion<double>(MaximumIterations), new ResidualStopCriterion<double>(ConvergenceBoundary), new DivergenceStopCriterion<double>(), new FailureStopCriterion<double>()); var solver = new MlkBiCgStab(); // 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, Math.Abs(y[i] - z[i]), "#05-" + i); } }
public void CanSolveForRandomVector(int order) { var matrixA = Matrix<double>.Build.Random(order, order, 1); var vectorb = Vector<double>.Build.Random(order, 1); var monitor = new Iterator<double>( new IterationCountStopCriterion<double>(1000), new ResidualStopCriterion<double>(1e-10)); var solver = new MlkBiCgStab(); var resultx = matrixA.SolveIterative(vectorb, solver, monitor); Assert.AreEqual(matrixA.ColumnCount, resultx.Count); var matrixBReconstruct = matrixA*resultx; // Check the reconstruction. for (var i = 0; i < order; i++) { Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-7); } }
public void SolvePoissonMatrixAndBackMultiply() { // Create the matrix var matrix = Matrix<double>.Build.Sparse(100, 100); // Assemble the matrix. We assume we're solving the Poisson equation // on a rectangular 10 x 10 grid const int GridSize = 10; // 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<double>.Build.Dense(matrix.RowCount, 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<double>( new IterationCountStopCriterion<double>(MaximumIterations), new ResidualStopCriterion<double>(ConvergenceBoundary), new DivergenceStopCriterion<double>(), new FailureStopCriterion<double>()); var solver = new MlkBiCgStab(); // 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, Math.Abs(y[i] - z[i]), "#05-" + i); } }
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(); }
/// <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, "matrix"); } if (result.Count != input.Count) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } if (iterator == null) { iterator = new Iterator <double>(); } if (preconditioner == null) { preconditioner = new UnitPreconditioner <double>(); } // 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); } } }
public void DetermineStatusWithNegativeIterationNumberThrowsArgumentOutOfRangeException() { var criteria = new List<IIterationStopCriterium<double>> { new FailureStopCriterium(), new DivergenceStopCriterium(), new IterationCountStopCriterium<double>(), new ResidualStopCriterium() }; var iterator = new Iterator<double>(criteria); Assert.Throws<ArgumentOutOfRangeException>(() => iterator.DetermineStatus( -1, DenseVector.Create(3, i => 4), DenseVector.Create(3, i => 5), DenseVector.Create(3, i => 6))); }
public void CanSolveForRandomVector(int order) { var matrixA = MatrixLoader.GenerateRandomDenseMatrix(order, order); var vectorb = MatrixLoader.GenerateRandomDenseVector(order); var monitor = new Iterator<double>(new IIterationStopCriterium<double>[] { new IterationCountStopCriterium<double>(1000), new ResidualStopCriterium(1e-10), }); var solver = new TFQMR(monitor); var resultx = solver.Solve(matrixA, vectorb); Assert.AreEqual(matrixA.ColumnCount, resultx.Count); var matrixBReconstruct = matrixA*resultx; // Check the reconstruction. for (var i = 0; i < order; i++) { Assert.AreEqual(vectorb[i], matrixBReconstruct[i], 1e-7); } }
public void SolvePoissonMatrixAndBackMultiply() { // Create the matrix var matrix = new SparseMatrix(100); // Assemble the matrix. We assume we're solving the Poisson equation // on a rectangular 10 x 10 grid const int GridSize = 10; // 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<double>(new IIterationStopCriterium<double>[] { new IterationCountStopCriterium<double>(MaximumIterations), new ResidualStopCriterium(ConvergenceBoundary), new DivergenceStopCriterium(), new FailureStopCriterium() }); var solver = new MlkBiCgStab(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++) { #if !PORTABLE Assert.IsTrue(Math.Abs(y[i] - z[i]).IsSmaller(ConvergenceBoundary, 1), "#05-" + i); #else Assert.IsTrue(Math.Abs(y[i] - z[i]).IsSmaller(ConvergenceBoundary * 100.0, 1), "#05-" + i); #endif } }
public void SolveScaledUnitMatrixAndBackMultiply() { // Create the identity matrix var matrix = Matrix<double>.Build.SparseIdentity(100); // Scale it with a funny number matrix.Multiply(Math.PI, matrix); // Create the y vector var y = Vector<double>.Build.Dense(matrix.RowCount, 1); // Create an iteration monitor which will keep track of iterative convergence var monitor = new Iterator<double>( new IterationCountStopCriterion<double>(MaximumIterations), new ResidualStopCriterion<double>(ConvergenceBoundary), new DivergenceStopCriterion<double>(), new FailureStopCriterion<double>()); 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> /// Run example /// </summary> public void Run() { // Format matrix output to console var formatProvider = (CultureInfo)CultureInfo.InvariantCulture.Clone(); formatProvider.TextInfo.ListSeparator = " "; // Solve next system of linear equations (Ax=b): // 5*x + 2*y - 4*z = -7 // 3*x - 7*y + 6*z = 38 // 4*x + 1*y + 5*z = 43 // Create matrix "A" with coefficients var matrixA = new DenseMatrix(new[,] { { 5.00, 2.00, -4.00 }, { 3.00, -7.00, 6.00 }, { 4.00, 1.00, 5.00 } }); Console.WriteLine(@"Matrix 'A' with coefficients"); Console.WriteLine(matrixA.ToString("#0.00\t", formatProvider)); Console.WriteLine(); // Create vector "b" with the constant terms. var vectorB = new DenseVector(new[] { -7.0, 38.0, 43.0 }); Console.WriteLine(@"Vector 'b' with the constant terms"); Console.WriteLine(vectorB.ToString("#0.00\t", formatProvider)); Console.WriteLine(); // Create stop criteriums to monitor an iterative calculation. There are next available stop criteriums: // - DivergenceStopCriterium: monitors an iterative calculation for signs of divergence; // - FailureStopCriterium: monitors residuals for NaN's; // - IterationCountStopCriterium: monitors the numbers of iteration steps; // - ResidualStopCriterium: monitors residuals if calculation is considered converged; // Stop calculation if 1000 iterations reached during calculation var iterationCountStopCriterium = new IterationCountStopCriterium(1000); // Stop calculation if residuals are below 1E-10 --> the calculation is considered converged var residualStopCriterium = new ResidualStopCriterium(1e-10); // Create monitor with defined stop criteriums var monitor = new Iterator(new IIterationStopCriterium[] { iterationCountStopCriterium, residualStopCriterium }); // Load all suitable solvers from current assembly. Below in this example, there is user-defined solver // "class UserBiCgStab : IIterativeSolverSetup<double>" which uses regular BiCgStab solver. But user may create any other solver // and solver setup classes which implement IIterativeSolverSetup<T> and pass assembly to next function: CompositeSolver.LoadSolverInformationFromAssembly(Assembly.GetExecutingAssembly()); // Create composite solver var solver = new CompositeSolver(monitor); // 1. Solve the matrix equation var resultX = solver.Solve(matrixA, vectorB); Console.WriteLine(@"1. Solve the matrix equation"); Console.WriteLine(); // 2. Check solver status of the iterations. // Solver has property IterationResult which contains the status of the iteration once the calculation is finished. // Possible values are: // - CalculationCancelled: calculation was cancelled by the user; // - CalculationConverged: calculation has converged to the desired convergence levels; // - CalculationDiverged: calculation diverged; // - CalculationFailure: calculation has failed for some reason; // - CalculationIndetermined: calculation is indetermined, not started or stopped; // - CalculationRunning: calculation is running and no results are yet known; // - CalculationStoppedWithoutConvergence: calculation has been stopped due to reaching the stopping limits, but that convergence was not achieved; Console.WriteLine(@"2. Solver status of the iterations"); Console.WriteLine(solver.IterationResult); Console.WriteLine(); // 3. Solution result vector of the matrix equation Console.WriteLine(@"3. Solution result vector of the matrix equation"); Console.WriteLine(resultX.ToString("#0.00\t", formatProvider)); Console.WriteLine(); // 4. Verify result. Multiply coefficient matrix "A" by result vector "x" var reconstructVecorB = matrixA * resultX; Console.WriteLine(@"4. Multiply coefficient matrix 'A' by result vector 'x'"); Console.WriteLine(reconstructVecorB.ToString("#0.00\t", formatProvider)); Console.WriteLine(); }
/// <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(Resource.ArgumentMatrixSquare, "matrix"); } if (result.Count != input.Count) { throw new ArgumentException(Resource.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); 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 double alpha = 0; double eta = 0; double theta = 0; // Initialize var tau = input.L2Norm(); var 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 = v.DotProduct(r); if (sigma.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 = pseudoResiduals.L2Norm() / tau; var c = 1 / 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.AlmostEqualNumbersBetween(0, 1)) { // FAIL HERE iterator.Cancel(); break; } var rhoNew = pseudoResiduals.DotProduct(r); 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++; } }
/// <summary> /// Run example /// </summary> public void Run() { // Format matrix output to console var formatProvider = (CultureInfo)CultureInfo.InvariantCulture.Clone(); formatProvider.TextInfo.ListSeparator = " "; // Solve next system of linear equations (Ax=b): // 5*x + 2*y - 4*z = -7 // 3*x - 7*y + 6*z = 38 // 4*x + 1*y + 5*z = 43 // Create matrix "A" with coefficients var matrixA = DenseMatrix.OfArray(new[,] { { 5.00, 2.00, -4.00 }, { 3.00, -7.00, 6.00 }, { 4.00, 1.00, 5.00 } }); Console.WriteLine(@"Matrix 'A' with coefficients"); Console.WriteLine(matrixA.ToString("#0.00\t", formatProvider)); Console.WriteLine(); // Create vector "b" with the constant terms. var vectorB = new DenseVector(new[] { -7.0, 38.0, 43.0 }); Console.WriteLine(@"Vector 'b' with the constant terms"); Console.WriteLine(vectorB.ToString("#0.00\t", formatProvider)); Console.WriteLine(); // Create stop criteriums to monitor an iterative calculation. There are next available stop criteriums: // - DivergenceStopCriterium: monitors an iterative calculation for signs of divergence; // - FailureStopCriterium: monitors residuals for NaN's; // - IterationCountStopCriterium: monitors the numbers of iteration steps; // - ResidualStopCriterium: monitors residuals if calculation is considered converged; // Stop calculation if 1000 iterations reached during calculation var iterationCountStopCriterium = new IterationCountStopCriterium<double>(1000); // Stop calculation if residuals are below 1E-10 --> the calculation is considered converged var residualStopCriterium = new ResidualStopCriterium(1e-10); // Create monitor with defined stop criteriums var monitor = new Iterator<double>(new IIterationStopCriterium<double>[] { iterationCountStopCriterium, residualStopCriterium }); // Create Transpose Free Quasi-Minimal Residual solver var solver = new TFQMR(monitor); // 1. Solve the matrix equation var resultX = solver.Solve(matrixA, vectorB); Console.WriteLine(@"1. Solve the matrix equation"); Console.WriteLine(); // 2. Check solver status of the iterations. // Solver has property IterationResult which contains the status of the iteration once the calculation is finished. // Possible values are: // - CalculationCancelled: calculation was cancelled by the user; // - CalculationConverged: calculation has converged to the desired convergence levels; // - CalculationDiverged: calculation diverged; // - CalculationFailure: calculation has failed for some reason; // - CalculationIndetermined: calculation is indetermined, not started or stopped; // - CalculationRunning: calculation is running and no results are yet known; // - CalculationStoppedWithoutConvergence: calculation has been stopped due to reaching the stopping limits, but that convergence was not achieved; Console.WriteLine(@"2. Solver status of the iterations"); Console.WriteLine(solver.IterationResult); Console.WriteLine(); // 3. Solution result vector of the matrix equation Console.WriteLine(@"3. Solution result vector of the matrix equation"); Console.WriteLine(resultX.ToString("#0.00\t", formatProvider)); Console.WriteLine(); // 4. Verify result. Multiply coefficient matrix "A" by result vector "x" var reconstructVecorB = matrixA * resultX; Console.WriteLine(@"4. Multiply coefficient matrix 'A' by result vector 'x'"); Console.WriteLine(reconstructVecorB.ToString("#0.00\t", formatProvider)); Console.WriteLine(); }
/// <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) { 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); // 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 double currentRho = 0; double alpha = 0; double 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.DotProduct(residuals); // if (rho_(i-1) == 0) // METHOD FAILS // If rho is only 1 ULP from zero then we fail. if (currentRho.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.DotProduct(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.DotProduct(vecS) / temp.DotProduct(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.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++; } }