Browse Source

LA: drop iterative solver manual-stop functionality (to be replaced)

optimization-1
Christoph Ruegg 13 years ago
parent
commit
d5104df7a3
  1. 158
      src/Numerics/LinearAlgebra/Complex/Solvers/BiCgStab.cs
  2. 112
      src/Numerics/LinearAlgebra/Complex/Solvers/CompositeSolver.cs
  3. 191
      src/Numerics/LinearAlgebra/Complex/Solvers/GpBiCg.cs
  4. 322
      src/Numerics/LinearAlgebra/Complex/Solvers/MlkBiCgStab.cs
  5. 166
      src/Numerics/LinearAlgebra/Complex/Solvers/TFQMR.cs
  6. 158
      src/Numerics/LinearAlgebra/Complex32/Solvers/BiCgStab.cs
  7. 112
      src/Numerics/LinearAlgebra/Complex32/Solvers/CompositeSolver.cs
  8. 191
      src/Numerics/LinearAlgebra/Complex32/Solvers/GpBiCg.cs
  9. 321
      src/Numerics/LinearAlgebra/Complex32/Solvers/MlkBiCgStab.cs
  10. 166
      src/Numerics/LinearAlgebra/Complex32/Solvers/TFQMR.cs
  11. 158
      src/Numerics/LinearAlgebra/Double/Solvers/BiCgStab.cs
  12. 112
      src/Numerics/LinearAlgebra/Double/Solvers/CompositeSolver.cs
  13. 191
      src/Numerics/LinearAlgebra/Double/Solvers/GpBiCg.cs
  14. 308
      src/Numerics/LinearAlgebra/Double/Solvers/MlkBiCgStab.cs
  15. 166
      src/Numerics/LinearAlgebra/Double/Solvers/TFQMR.cs
  16. 158
      src/Numerics/LinearAlgebra/Single/Solvers/BiCgStab.cs
  17. 112
      src/Numerics/LinearAlgebra/Single/Solvers/CompositeSolver.cs
  18. 191
      src/Numerics/LinearAlgebra/Single/Solvers/GpBiCg.cs
  19. 316
      src/Numerics/LinearAlgebra/Single/Solvers/MlkBiCgStab.cs
  20. 166
      src/Numerics/LinearAlgebra/Single/Solvers/TFQMR.cs
  21. 8
      src/Numerics/LinearAlgebra/Solvers/IIterativeSolver.cs

158
src/Numerics/LinearAlgebra/Complex/Solvers/BiCgStab.cs

@ -73,44 +73,36 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
public sealed class BiCgStab : IIterativeSolver<Complex>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public BiCgStab()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
}
// -Ax = residual
matrix.Multiply(x, residual);
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
@ -122,32 +114,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param>
public void Solve(Matrix<Complex> matrix, Vector<Complex> input, Vector<Complex> result, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Parameters checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -321,63 +292,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -411,5 +325,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
}
/// <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="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

112
src/Numerics/LinearAlgebra/Complex/Solvers/CompositeSolver.cs

@ -65,57 +65,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// </summary>
readonly List<Tuple<IIterativeSolver<Complex>, IPreconditioner<Complex>>> _solvers;
/// <summary>
/// The status of the calculation.
/// </summary>
IterationStatus _status = IterationStatus.Indetermined;
/// <summary>
/// A flag indicating if the solver has been stopped or not.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// The solver that is currently running. Reference is used to be able to stop the
/// solver if the user cancels the solve process.
/// </summary>
IIterativeSolver<Complex> _currentSolver;
public CompositeSolver(IEnumerable<IIterativeSolverSetup<Complex>> solvers)
{
_solvers = solvers.Select(setup => new Tuple<IIterativeSolver<Complex>, IPreconditioner<Complex>>(setup.CreateSolver(), setup.CreatePreconditioner() ?? new UnitPreconditioner<Complex>())).ToList();
}
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
var currentSolver = _currentSolver;
if (currentSolver != null)
{
currentSolver.StopSolve();
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return 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.
@ -125,12 +79,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Complex> matrix, Vector<Complex> input, Vector<Complex> result, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
_currentSolver = null;
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
@ -153,11 +101,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
var internalInput = input.Clone();
var internalResult = result.Clone();
foreach (var solver in _solvers.TakeWhile(solver => !_hasBeenStopped))
foreach (var solver in _solvers)
{
// Store a reference to the solver so we can stop it.
_currentSolver = solver.Item1;
IterationStatus status;
try
{
// Reset the iterator and pass it to the solver
@ -165,7 +113,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
// Start the solver
solver.Item1.Solve(matrix, internalInput, internalResult, iterator, solver.Item2);
_status = iterator.Status;
status = iterator.Status;
}
catch (Exception)
{
@ -174,12 +122,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
// Switch to the next preconditioner.
// Reset the solution vector to the previous solution
input.CopyTo(internalInput);
_status = IterationStatus.Running;
continue;
}
// There was no fatal breakdown so check the status
if (_status == IterationStatus.Converged)
if (status == IterationStatus.Converged)
{
// We're done
internalResult.CopyTo(result);
@ -189,7 +136,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
// We're not done
// Either:
// - calculation finished without convergence
if (_status == IterationStatus.StoppedWithoutConvergence)
if (status == IterationStatus.StoppedWithoutConvergence)
{
// Copy the internal result to the result vector and
// continue with the calculation.
@ -203,27 +150,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
input.CopyTo(internalInput);
}
}
// Inside the loop we already copied the final results (if there are any)
// So no need to do that again.
// Clean up
// No longer need the current solver
_currentSolver = null;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
@ -259,5 +185,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

191
src/Numerics/LinearAlgebra/Complex/Solvers/GpBiCg.cs

@ -82,22 +82,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// </summary>
int _numberOfGpbiCgSteps = 4;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public GpBiCg()
{
}
/// <summary>
/// Gets or sets the number of steps taken with the <c>BiCgStab</c> algorithm
/// before switching over to the <c>GPBiCG</c> algorithm.
@ -137,29 +121,51 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
/// <summary>
/// Stops the solve process.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually
/// stop the process.
/// </remarks>
public void StopSolve()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
_hasBeenStopped = true;
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber % (_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
@ -171,32 +177,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Complex> matrix, Vector<Complex> input, Vector<Complex> result, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (input.Count != matrix.RowCount || result.Count != input.Count)
{
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix, input, result);
@ -406,78 +391,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber%(_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -511,5 +424,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

322
src/Numerics/LinearAlgebra/Complex/Solvers/MlkBiCgStab.cs

@ -32,7 +32,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra.Solvers;
using MathNet.Numerics.Properties;
@ -44,7 +43,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
using Complex = Numerics.Complex;
#else
using Complex = System.Numerics.Complex;
#endif
/// <summary>
@ -87,22 +85,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// </summary>
int _numberOfStartingVectors = DefaultNumberOfStartingVectors;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public MlkBiCgStab()
{
}
/// <summary>
/// Gets or sets the number of starting vectors.
/// </summary>
@ -159,30 +141,119 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
/// <summary>
/// Stops the solve process.
/// Gets the number of starting vectors to create
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
_hasBeenStopped = true;
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Returns an array of starting vectors.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<Complex>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = new Complex[matrix.RowCount];
var samplesRe = distribution.Samples().Take(matrix.RowCount).ToArray();
var samplesIm = distribution.Samples().Take(matrix.RowCount).ToArray();
for (int j = 0; j < matrix.RowCount; j++)
{
samples[j] = new Complex(samplesRe[j], samplesIm[j]);
}
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<Complex>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1 / result[i].L2Norm(), result[i]);
}
return result;
}
/// <summary>
/// Create random vecrors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<Complex>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<Complex>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
@ -192,32 +263,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Complex> matrix, Vector<Complex> input, Vector<Complex> result, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (input.Count != matrix.RowCount || result.Count != input.Count)
{
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix, input, result);
@ -506,144 +556,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
xtemp.CopyTo(result);
}
/// <summary>
/// Gets the number of starting vectors to create
/// </summary>
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Returns an array of starting vectors.
/// </summary>
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<Complex>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = new Complex[matrix.RowCount];
var samplesRe = distribution.Samples().Take(matrix.RowCount).ToArray();
var samplesIm = distribution.Samples().Take(matrix.RowCount).ToArray();
for (int j = 0; j < matrix.RowCount; j++)
{
samples[j] = new Complex(samplesRe[j], samplesIm[j]);
}
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<Complex>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1/result[i].L2Norm(), result[i]);
}
return result;
}
/// <summary>
/// Create random vecrors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<Complex>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<Complex>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -677,5 +589,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

166
src/Numerics/LinearAlgebra/Complex/Solvers/TFQMR.cs

@ -62,44 +62,44 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
public sealed class TFQMR : IIterativeSolver<Complex>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="TFQMR"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public TFQMR()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Stops the solve process.
/// Determine if calculation should continue
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
_hasBeenStopped = true;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
return number % 2 == 0;
}
/// <summary>
@ -111,32 +111,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Complex> matrix, Vector<Complex> input, Vector<Complex> result, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (input.Count != matrix.RowCount || result.Count != input.Count)
{
throw Matrix.DimensionsDontMatch<ArgumentException>(matrix, input, result);
@ -313,71 +292,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Complex> matrix, Vector<Complex> residual, Vector<Complex> x, Vector<Complex> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Complex> iterator, int iterationNumber, Vector<Complex> result, Vector<Complex> source, Vector<Complex> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
return number%2 == 0;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -411,5 +325,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Complex> Solve(Matrix<Complex> matrix, Vector<Complex> vector, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Complex> Solve(Matrix<Complex> matrix, Matrix<Complex> input, Iterator<Complex> iterator = null, IPreconditioner<Complex> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

158
src/Numerics/LinearAlgebra/Complex32/Solvers/BiCgStab.cs

@ -67,44 +67,36 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
public sealed class BiCgStab : IIterativeSolver<Numerics.Complex32>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public BiCgStab()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
}
// -Ax = residual
matrix.Multiply(x, residual);
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
@ -116,32 +108,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param>
public void Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> input, Vector<Numerics.Complex32> result, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Parameters checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -315,63 +286,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -405,5 +319,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
}
/// <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="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

112
src/Numerics/LinearAlgebra/Complex32/Solvers/CompositeSolver.cs

@ -58,57 +58,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// </summary>
readonly List<Tuple<IIterativeSolver<Numerics.Complex32>, IPreconditioner<Numerics.Complex32>>> _solvers;
/// <summary>
/// The status of the calculation.
/// </summary>
IterationStatus _status = IterationStatus.Indetermined;
/// <summary>
/// A flag indicating if the solver has been stopped or not.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// The solver that is currently running. Reference is used to be able to stop the
/// solver if the user cancels the solve process.
/// </summary>
IIterativeSolver<Numerics.Complex32> _currentSolver;
public CompositeSolver(IEnumerable<IIterativeSolverSetup<Numerics.Complex32>> solvers)
{
_solvers = solvers.Select(setup => new Tuple<IIterativeSolver<Numerics.Complex32>, IPreconditioner<Numerics.Complex32>>(setup.CreateSolver(), setup.CreatePreconditioner() ?? new UnitPreconditioner<Numerics.Complex32>())).ToList();
}
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
var currentSolver = _currentSolver;
if (currentSolver != null)
{
currentSolver.StopSolve();
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return 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.
@ -118,12 +72,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> input, Vector<Numerics.Complex32> result, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
_currentSolver = null;
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
@ -146,11 +94,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
var internalInput = input.Clone();
var internalResult = result.Clone();
foreach (var solver in _solvers.TakeWhile(solver => !_hasBeenStopped))
foreach (var solver in _solvers)
{
// Store a reference to the solver so we can stop it.
_currentSolver = solver.Item1;
IterationStatus status;
try
{
// Reset the iterator and pass it to the solver
@ -158,7 +106,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
// Start the solver
solver.Item1.Solve(matrix, internalInput, internalResult, iterator, solver.Item2);
_status = iterator.Status;
status = iterator.Status;
}
catch (Exception)
{
@ -167,12 +115,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
// Switch to the next preconditioner.
// Reset the solution vector to the previous solution
input.CopyTo(internalInput);
_status = IterationStatus.Running;
continue;
}
// There was no fatal breakdown so check the status
if (_status == IterationStatus.Converged)
if (status == IterationStatus.Converged)
{
// We're done
internalResult.CopyTo(result);
@ -182,7 +129,7 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
// We're not done
// Either:
// - calculation finished without convergence
if (_status == IterationStatus.StoppedWithoutConvergence)
if (status == IterationStatus.StoppedWithoutConvergence)
{
// Copy the internal result to the result vector and
// continue with the calculation.
@ -196,27 +143,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
input.CopyTo(internalInput);
}
}
// Inside the loop we already copied the final results (if there are any)
// So no need to do that again.
// Clean up
// No longer need the current solver
_currentSolver = null;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
@ -252,5 +178,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

191
src/Numerics/LinearAlgebra/Complex32/Solvers/GpBiCg.cs

@ -75,22 +75,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// </summary>
int _numberOfGpbiCgSteps = 4;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public GpBiCg()
{
}
/// <summary>
/// Gets or sets the number of steps taken with the <c>BiCgStab</c> algorithm
/// before switching over to the <c>GPBiCG</c> algorithm.
@ -130,29 +114,51 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
/// <summary>
/// Stops the solve process.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually
/// stop the process.
/// </remarks>
public void StopSolve()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
_hasBeenStopped = true;
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber % (_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
@ -164,32 +170,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> input, Vector<Numerics.Complex32> result, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -404,78 +389,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber%(_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -509,5 +422,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

321
src/Numerics/LinearAlgebra/Complex32/Solvers/MlkBiCgStab.cs

@ -33,7 +33,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.LinearAlgebra.Complex32.Solvers.Preconditioners;
using MathNet.Numerics.LinearAlgebra.Solvers;
using MathNet.Numerics.Properties;
@ -79,22 +78,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// </summary>
int _numberOfStartingVectors = DefaultNumberOfStartingVectors;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public MlkBiCgStab()
{
}
/// <summary>
/// Gets or sets the number of starting vectors.
/// </summary>
@ -151,30 +134,119 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
/// <summary>
/// Stops the solve process.
/// Gets the number of starting vectors to create
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
_hasBeenStopped = true;
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Returns an array of starting vectors.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<Numerics.Complex32>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = new Numerics.Complex32[matrix.RowCount];
var samplesRe = distribution.Samples().Take(matrix.RowCount).ToArray();
var samplesIm = distribution.Samples().Take(matrix.RowCount).ToArray();
for (int j = 0; j < matrix.RowCount; j++)
{
samples[j] = new Numerics.Complex32((float)samplesRe[j], (float)samplesIm[j]);
}
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<Numerics.Complex32>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1 / result[i].L2Norm().Real, result[i]);
}
return result;
}
/// <summary>
/// Create random vectors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<Numerics.Complex32>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<Numerics.Complex32>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
@ -184,32 +256,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> input, Vector<Numerics.Complex32> result, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -503,144 +554,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
xtemp.CopyTo(result);
}
/// <summary>
/// Gets the number of starting vectors to create
/// </summary>
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Returns an array of starting vectors.
/// </summary>
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<Numerics.Complex32>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = new Numerics.Complex32[matrix.RowCount];
var samplesRe = distribution.Samples().Take(matrix.RowCount).ToArray();
var samplesIm = distribution.Samples().Take(matrix.RowCount).ToArray();
for (int j = 0; j < matrix.RowCount; j++)
{
samples[j] = new Numerics.Complex32((float) samplesRe[j], (float) samplesIm[j]);
}
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<Numerics.Complex32>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1/result[i].L2Norm().Real, result[i]);
}
return result;
}
/// <summary>
/// Create random vectors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<Numerics.Complex32>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<Numerics.Complex32>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -674,5 +587,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

166
src/Numerics/LinearAlgebra/Complex32/Solvers/TFQMR.cs

@ -54,44 +54,44 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
public sealed class TFQMR : IIterativeSolver<Numerics.Complex32>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="TFQMR"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public TFQMR()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Stops the solve process.
/// Determine if calculation should continue
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
_hasBeenStopped = true;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
return number % 2 == 0;
}
/// <summary>
@ -103,32 +103,11 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> input, Vector<Numerics.Complex32> result, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -310,71 +289,6 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> residual, Vector<Numerics.Complex32> x, Vector<Numerics.Complex32> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<Numerics.Complex32> iterator, int iterationNumber, Vector<Numerics.Complex32> result, Vector<Numerics.Complex32> source, Vector<Numerics.Complex32> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
return number%2 == 0;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -408,5 +322,33 @@ namespace MathNet.Numerics.LinearAlgebra.Complex32.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Vector<Numerics.Complex32> vector, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<Numerics.Complex32> Solve(Matrix<Numerics.Complex32> matrix, Matrix<Numerics.Complex32> input, Iterator<Numerics.Complex32> iterator = null, IPreconditioner<Numerics.Complex32> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

158
src/Numerics/LinearAlgebra/Double/Solvers/BiCgStab.cs

@ -66,44 +66,36 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
public sealed class BiCgStab : IIterativeSolver<double>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public BiCgStab()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
}
// -Ax = residual
matrix.Multiply(x, residual);
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// It may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
@ -115,32 +107,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param>
public void Solve(Matrix<double> matrix, Vector<double> input, Vector<double> result, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Parameters checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -314,63 +285,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -404,5 +318,33 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
}
/// <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="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

112
src/Numerics/LinearAlgebra/Double/Solvers/CompositeSolver.cs

@ -58,57 +58,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// </summary>
readonly List<Tuple<IIterativeSolver<double>, IPreconditioner<double>>> _solvers;
/// <summary>
/// The status of the calculation.
/// </summary>
IterationStatus _status = IterationStatus.Indetermined;
/// <summary>
/// A flag indicating if the solver has been stopped or not.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// The solver that is currently running. Reference is used to be able to stop the
/// solver if the user cancels the solve process.
/// </summary>
IIterativeSolver<double> _currentSolver;
public CompositeSolver(IEnumerable<IIterativeSolverSetup<double>> solvers)
{
_solvers = solvers.Select(setup => new Tuple<IIterativeSolver<double>, IPreconditioner<double>>(setup.CreateSolver(), setup.CreatePreconditioner() ?? new UnitPreconditioner<double>())).ToList();
}
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
var currentSolver = _currentSolver;
if (currentSolver != null)
{
currentSolver.StopSolve();
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return 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.
@ -118,12 +72,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<double> matrix, Vector<double> input, Vector<double> result, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
_currentSolver = null;
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
@ -146,11 +94,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
var internalInput = input.Clone();
var internalResult = result.Clone();
foreach (var solver in _solvers.TakeWhile(solver => !_hasBeenStopped))
foreach (var solver in _solvers)
{
// Store a reference to the solver so we can stop it.
_currentSolver = solver.Item1;
IterationStatus status;
try
{
// Reset the iterator and pass it to the solver
@ -158,7 +106,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
// Start the solver
solver.Item1.Solve(matrix, internalInput, internalResult, iterator, solver.Item2);
_status = iterator.Status;
status = iterator.Status;
}
catch (Exception)
{
@ -167,12 +115,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
// Switch to the next preconditioner.
// Reset the solution vector to the previous solution
input.CopyTo(internalInput);
_status = IterationStatus.Running;
continue;
}
// There was no fatal breakdown so check the status
if (_status == IterationStatus.Converged)
if (status == IterationStatus.Converged)
{
// We're done
internalResult.CopyTo(result);
@ -182,7 +129,7 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
// We're not done
// Either:
// - calculation finished without convergence
if (_status == IterationStatus.StoppedWithoutConvergence)
if (status == IterationStatus.StoppedWithoutConvergence)
{
// Copy the internal result to the result vector and
// continue with the calculation.
@ -196,27 +143,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
input.CopyTo(internalInput);
}
}
// Inside the loop we already copied the final results (if there are any)
// So no need to do that again.
// Clean up
// No longer need the current solver
_currentSolver = null;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
@ -252,5 +178,33 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

191
src/Numerics/LinearAlgebra/Double/Solvers/GpBiCg.cs

@ -75,22 +75,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// </summary>
int _numberOfGpbiCgSteps = 4;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public GpBiCg()
{
}
/// <summary>
/// Gets or sets the number of steps taken with the <c>BiCgStab</c> algorithm
/// before switching over to the <c>GPBiCG</c> algorithm.
@ -136,29 +120,51 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
/// <summary>
/// Stops the solve process.
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually
/// stop the process.
/// </remarks>
public void StopSolve()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
_hasBeenStopped = true;
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber % (_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
@ -170,32 +176,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<double> matrix, Vector<double> input, Vector<double> result, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -410,78 +395,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
/// <summary>
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber%(_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -515,5 +428,33 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

308
src/Numerics/LinearAlgebra/Double/Solvers/MlkBiCgStab.cs

@ -78,22 +78,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// </summary>
int _numberOfStartingVectors = DefaultNumberOfStartingVectors;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public MlkBiCgStab()
{
}
/// <summary>
/// Gets or sets the number of starting vectors.
/// </summary>
@ -156,30 +140,113 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
/// <summary>
/// Stops the solve process.
/// Gets the number of starting vectors to create
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
_hasBeenStopped = true;
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Returns an array of starting vectors.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<double>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = distribution.Samples().Take(matrix.RowCount).ToArray();
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<double>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1 / result[i].L2Norm(), result[i]);
}
return result;
}
/// <summary>
/// Create random vecrors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<double>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<double>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
@ -189,32 +256,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<double> matrix, Vector<double> input, Vector<double> result, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -508,138 +554,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
xtemp.CopyTo(result);
}
/// <summary>
/// Gets the number of starting vectors to create
/// </summary>
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Returns an array of starting vectors.
/// </summary>
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<double>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = distribution.Samples().Take(matrix.RowCount).ToArray();
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<double>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1/result[i].L2Norm(), result[i]);
}
return result;
}
/// <summary>
/// Create random vecrors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<double>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<double>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the true residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -673,5 +587,33 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

166
src/Numerics/LinearAlgebra/Double/Solvers/TFQMR.cs

@ -54,44 +54,44 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
public sealed class TFQMR : IIterativeSolver<double>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="TFQMR"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public TFQMR()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Stops the solve process.
/// Determine if calculation should continue
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
_hasBeenStopped = true;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
return number % 2 == 0;
}
/// <summary>
@ -103,32 +103,11 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<double> matrix, Vector<double> input, Vector<double> result, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -310,71 +289,6 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<double> matrix, Vector<double> residual, Vector<double> x, Vector<double> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<double> iterator, int iterationNumber, Vector<double> result, Vector<double> source, Vector<double> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
return number%2 == 0;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -408,5 +322,33 @@ namespace MathNet.Numerics.LinearAlgebra.Double.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<double> Solve(Matrix<double> matrix, Vector<double> vector, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<double> Solve(Matrix<double> matrix, Matrix<double> input, Iterator<double> iterator = null, IPreconditioner<double> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

158
src/Numerics/LinearAlgebra/Single/Solvers/BiCgStab.cs

@ -66,44 +66,36 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
public sealed class BiCgStab : IIterativeSolver<float>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="BiCgStab"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public BiCgStab()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
}
// -Ax = residual
matrix.Multiply(x, residual);
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
@ -115,32 +107,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param>
public void Solve(Matrix<float> matrix, Vector<float> input, Vector<float> result, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Parameters checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -314,63 +285,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
// Do not use residual = residual.Negate() because it creates another object
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -404,5 +318,33 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
}
/// <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="vector">The solution <see cref="Vector"/>, <c>b</c>.</param>
/// <returns>The result <see cref="Vector"/>, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
/// <param name="input">The solution <see cref="Matrix"/>, <c>B</c>.</param>
/// <returns>The result <see cref="Matrix"/>, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

112
src/Numerics/LinearAlgebra/Single/Solvers/CompositeSolver.cs

@ -58,57 +58,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// </summary>
readonly List<Tuple<IIterativeSolver<float>, IPreconditioner<float>>> _solvers;
/// <summary>
/// The status of the calculation.
/// </summary>
IterationStatus _status = IterationStatus.Indetermined;
/// <summary>
/// A flag indicating if the solver has been stopped or not.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// The solver that is currently running. Reference is used to be able to stop the
/// solver if the user cancels the solve process.
/// </summary>
IIterativeSolver<float> _currentSolver;
public CompositeSolver(IEnumerable<IIterativeSolverSetup<float>> solvers)
{
_solvers = solvers.Select(setup => new Tuple<IIterativeSolver<float>, IPreconditioner<float>>(setup.CreateSolver(), setup.CreatePreconditioner() ?? new UnitPreconditioner<float>())).ToList();
}
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
{
_hasBeenStopped = true;
var currentSolver = _currentSolver;
if (currentSolver != null)
{
currentSolver.StopSolve();
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return 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.
@ -118,12 +72,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<float> matrix, Vector<float> input, Vector<float> result, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
_currentSolver = null;
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
@ -146,11 +94,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
var internalInput = input.Clone();
var internalResult = result.Clone();
foreach (var solver in _solvers.TakeWhile(solver => !_hasBeenStopped))
foreach (var solver in _solvers)
{
// Store a reference to the solver so we can stop it.
_currentSolver = solver.Item1;
IterationStatus status;
try
{
// Reset the iterator and pass it to the solver
@ -158,7 +106,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
// Start the solver
solver.Item1.Solve(matrix, internalInput, internalResult, iterator, solver.Item2);
_status = iterator.Status;
status = iterator.Status;
}
catch (Exception)
{
@ -167,12 +115,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
// Switch to the next preconditioner.
// Reset the solution vector to the previous solution
input.CopyTo(internalInput);
_status = IterationStatus.Running;
continue;
}
// There was no fatal breakdown so check the status
if (_status == IterationStatus.Converged)
if (status == IterationStatus.Converged)
{
// We're done
internalResult.CopyTo(result);
@ -182,7 +129,7 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
// We're not done
// Either:
// - calculation finished without convergence
if (_status == IterationStatus.StoppedWithoutConvergence)
if (status == IterationStatus.StoppedWithoutConvergence)
{
// Copy the internal result to the result vector and
// continue with the calculation.
@ -196,27 +143,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
input.CopyTo(internalInput);
}
}
// Inside the loop we already copied the final results (if there are any)
// So no need to do that again.
// Clean up
// No longer need the current solver
_currentSolver = null;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
@ -252,5 +178,33 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

191
src/Numerics/LinearAlgebra/Single/Solvers/GpBiCg.cs

@ -75,22 +75,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// </summary>
int _numberOfGpbiCgSteps = 4;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="GpBiCg"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public GpBiCg()
{
}
/// <summary>
/// Gets or sets the number of steps taken with the <c>BiCgStab</c> algorithm
/// before switching over to the <c>GPBiCG</c> algorithm.
@ -130,29 +114,51 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
/// <summary>
/// Stops the solve process.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually
/// stop the process.
/// </remarks>
public void StopSolve()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
_hasBeenStopped = true;
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Determine if calculation should continue
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber % (_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
@ -164,32 +170,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<float> matrix, Vector<float> input, Vector<float> result, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -404,78 +389,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Decide if to do steps with BiCgStab
/// </summary>
/// <param name="iterationNumber">Number of iteration</param>
/// <returns><c>true</c> if yes, otherwise <c>false</c></returns>
bool ShouldRunBiCgStabSteps(int iterationNumber)
{
// Run the first steps as BiCGStab
// The number of steps past a whole iteration set
var difference = iterationNumber%(_numberOfBiCgStabSteps + _numberOfGpbiCgSteps);
// Do steps with BiCGStab if:
// - The difference is zero or more (i.e. we have done zero or more complete cycles)
// - The difference is less than the number of BiCGStab steps that should be taken
return (difference >= 0) && (difference < _numberOfBiCgStabSteps);
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -509,5 +422,33 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

316
src/Numerics/LinearAlgebra/Single/Solvers/MlkBiCgStab.cs

@ -77,22 +77,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// </summary>
int _numberOfStartingVectors = DefaultNumberOfStartingVectors;
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="MlkBiCgStab"/> class.
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public MlkBiCgStab()
{
}
/// <summary>
/// Gets or sets the number of starting vectors.
/// </summary>
@ -155,30 +139,117 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
/// <summary>
/// Stops the solve process.
/// Gets the number of starting vectors to create
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
_hasBeenStopped = true;
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Returns an array of starting vectors.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<float>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = new float[matrix.RowCount];
for (var j = 0; j < matrix.RowCount; j++)
{
samples[j] = (float)distribution.Sample();
}
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<float>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1 / result[i].L2Norm(), result[i]);
}
return result;
}
/// <summary>
/// Create random vectors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<float>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<float>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
@ -188,32 +259,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<float> matrix, Vector<float> input, Vector<float> result, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -507,142 +557,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
xtemp.CopyTo(result);
}
/// <summary>
/// Gets the number of starting vectors to create
/// </summary>
/// <param name="maximumNumberOfStartingVectors">Maximum number</param>
/// <param name="numberOfVariables">Number of variables</param>
/// <returns>Number of starting vectors to create</returns>
static int NumberOfStartingVectorsToCreate(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
return Math.Min(maximumNumberOfStartingVectors, (numberOfVariables - 1));
}
/// <summary>
/// Returns an array of starting vectors.
/// </summary>
/// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
/// <param name="numberOfVariables">The number of variables.</param>
/// <returns>
/// An array with starting vectors. The array will never be larger than the
/// <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
/// the <paramref name="numberOfVariables"/> is smaller than
/// the <paramref name="maximumNumberOfStartingVectors"/>.
/// </returns>
static IList<Vector<float>> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
{
// Create no more starting vectors than the size of the problem - 1
// Get random values and then orthogonalize them with
// modified Gramm - Schmidt
var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);
// Get a random set of samples based on the standard normal distribution with
// mean = 0 and sd = 1
var distribution = new Normal();
var matrix = new DenseMatrix(numberOfVariables, count);
for (var i = 0; i < matrix.ColumnCount; i++)
{
var samples = new float[matrix.RowCount];
for (var j = 0; j < matrix.RowCount; j++)
{
samples[j] = (float) distribution.Sample();
}
// Set the column
matrix.SetColumn(i, samples);
}
// Compute the orthogonalization.
var gs = matrix.GramSchmidt();
var orthogonalMatrix = gs.Q;
// Now transfer this to vectors
var result = new List<Vector<float>>();
for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
{
result.Add(orthogonalMatrix.Column(i));
// Normalize the result vector
result[i].Multiply(1/result[i].L2Norm(), result[i]);
}
return result;
}
/// <summary>
/// Create random vectors array
/// </summary>
/// <param name="arraySize">Number of vectors</param>
/// <param name="vectorSize">Size of each vector</param>
/// <returns>Array of random vectors</returns>
static Vector<float>[] CreateVectorArray(int arraySize, int vectorSize)
{
var result = new Vector<float>[arraySize];
for (var i = 0; i < result.Length; i++)
{
result[i] = new DenseVector(vectorSize);
}
return result;
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Source <see cref="Matrix"/>A.</param>
/// <param name="residual">Residual <see cref="Vector"/> data.</param>
/// <param name="x">x <see cref="Vector"/> data.</param>
/// <param name="b">b <see cref="Vector"/> data.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -676,5 +590,33 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

166
src/Numerics/LinearAlgebra/Single/Solvers/TFQMR.cs

@ -54,44 +54,44 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
public sealed class TFQMR : IIterativeSolver<float>
{
/// <summary>
/// Indicates if the user has stopped the solver.
/// </summary>
bool _hasBeenStopped;
/// <summary>
/// Initializes a new instance of the <see cref="TFQMR"/> class.
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <remarks>
/// When using this constructor the solver will use the <see cref="Iterator{T}"/> with
/// the standard settings and a default preconditioner.
/// </remarks>
public TFQMR()
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Stops the solve process.
/// Determine if calculation should continue
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
public void StopSolve()
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
static bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
_hasBeenStopped = true;
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
return number % 2 == 0;
}
/// <summary>
@ -103,32 +103,11 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
/// <param name="result">The result vector, <c>x</c></param>
public void Solve(Matrix<float> matrix, Vector<float> input, Vector<float> result, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
// If we were stopped before, we are no longer
// We're doing this at the start of the method to ensure
// that we can use these fields immediately.
_hasBeenStopped = false;
// Error checks
if (matrix == null)
{
throw new ArgumentNullException("matrix");
}
if (matrix.RowCount != matrix.ColumnCount)
{
throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
}
if (input == null)
{
throw new ArgumentNullException("input");
}
if (result == null)
{
throw new ArgumentNullException("result");
}
if (result.Count != input.Count)
{
throw new ArgumentException(Resources.ArgumentVectorsSameLength);
@ -310,71 +289,6 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
/// <summary>
/// Calculates the <c>true</c> residual of the matrix equation Ax = b according to: residual = b - Ax
/// </summary>
/// <param name="matrix">Instance of the <see cref="Matrix"/> A.</param>
/// <param name="residual">Residual values in <see cref="Vector"/>.</param>
/// <param name="x">Instance of the <see cref="Vector"/> x.</param>
/// <param name="b">Instance of the <see cref="Vector"/> b.</param>
static void CalculateTrueResidual(Matrix<float> matrix, Vector<float> residual, Vector<float> x, Vector<float> b)
{
// -Ax = residual
matrix.Multiply(x, residual);
residual.Multiply(-1, residual);
// residual + b
residual.Add(b, residual);
}
/// <summary>
/// Determine if calculation should continue
/// </summary>
/// <param name="iterationNumber">Number of iterations passed</param>
/// <param name="result">Result <see cref="Vector"/>.</param>
/// <param name="source">Source <see cref="Vector"/>.</param>
/// <param name="residuals">Residual <see cref="Vector"/>.</param>
/// <returns><c>true</c> if continue, otherwise <c>false</c></returns>
bool ShouldContinue(Iterator<float> iterator, int iterationNumber, Vector<float> result, Vector<float> source, Vector<float> residuals)
{
// We stop if either:
// - the user has stopped the calculation
// - the calculation needs to be stopped from a numerical point of view (divergence, convergence etc.)
if (_hasBeenStopped)
{
iterator.Cancel();
return true;
}
var status = iterator.DetermineStatus(iterationNumber, result, source, residuals);
return status == IterationStatus.Running || status == IterationStatus.Indetermined;
}
/// <summary>
/// Is <paramref name="number"/> even?
/// </summary>
/// <param name="number">Number to check</param>
/// <returns><c>true</c> if <paramref name="number"/> even, otherwise <c>false</c></returns>
static bool IsEven(int number)
{
return number%2 == 0;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
@ -408,5 +322,33 @@ namespace MathNet.Numerics.LinearAlgebra.Single.Solvers
}
}
}
/// <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="vector">The solution vector, <c>b</c>.</param>
/// <returns>The result vector, <c>x</c>.</returns>
public Vector<float> Solve(Matrix<float> matrix, Vector<float> vector, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = new DenseVector(matrix.RowCount);
Solve(matrix, vector, result, iterator, preconditioner);
return result;
}
/// <summary>
/// Solves the matrix equation AX = B, where A is the coefficient matrix, B is the
/// solution matrix and X is the unknown matrix.
/// </summary>
/// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
/// <param name="input">The solution matrix, <c>B</c>.</param>
/// <returns>The result matrix, <c>X</c>.</returns>
public Matrix<float> Solve(Matrix<float> matrix, Matrix<float> input, Iterator<float> iterator = null, IPreconditioner<float> preconditioner = null)
{
var result = matrix.CreateMatrix(input.RowCount, input.ColumnCount);
Solve(matrix, input, result, iterator, preconditioner);
return result;
}
}
}

8
src/Numerics/LinearAlgebra/Solvers/IIterativeSolver.cs

@ -38,14 +38,6 @@ namespace MathNet.Numerics.LinearAlgebra.Solvers
/// </summary>
public interface IIterativeSolver<T> where T : struct, IEquatable<T>, IFormattable
{
/// <summary>
/// Stops the solve process.
/// </summary>
/// <remarks>
/// Note that it may take an indetermined amount of time for the solver to actually stop the process.
/// </remarks>
void StopSolve();
/// <summary>
/// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
/// solution vector and x is the unknown vector.

Loading…
Cancel
Save