/// <summary> /// Approximates the solution to the matrix equation <b>Ax = b</b>. /// </summary> /// <param name="rhs">The right hand side vector.</param> /// <param name="lhs">The left hand side vector. Also known as the result vector.</param> public void Approximate(Vector <Complex32> rhs, Vector <Complex32> lhs) { if (_decompositionLU == null) { throw new ArgumentException("The requested matrix does not exist."); } if ((lhs.Count != rhs.Count) || (lhs.Count != _decompositionLU.RowCount)) { throw new ArgumentException("All vectors must have the same dimensionality."); } // Solve: // Lz = y // Which gives // for (int i = 1; i < matrix.RowLength; i++) // { // z_i = l_ii^-1 * (y_i - SUM_(j<i) l_ij * z_j) // } // NOTE: l_ii should be 1 because u_ii has to be the value var rowValues = new DenseVector(_decompositionLU.RowCount); for (var i = 0; i < _decompositionLU.RowCount; i++) { // Clear the rowValues rowValues.Clear(); _decompositionLU.Row(i, rowValues); var sum = Complex32.Zero; for (var j = 0; j < i; j++) { sum += rowValues[j] * lhs[j]; } lhs[i] = rhs[i] - sum; } // Solve: // Ux = z // Which gives // for (int i = matrix.RowLength - 1; i > -1; i--) // { // x_i = u_ii^-1 * (z_i - SUM_(j > i) u_ij * x_j) // } for (var i = _decompositionLU.RowCount - 1; i > -1; i--) { _decompositionLU.Row(i, rowValues); var sum = Complex32.Zero; for (var j = _decompositionLU.RowCount - 1; j > i; j--) { sum += rowValues[j] * lhs[j]; } lhs[i] = 1 / rowValues[i] * (lhs[i] - sum); } }
/// <summary> /// Approximates the solution to the matrix equation <b>Ax = b</b>. /// </summary> /// <param name="rhs">The right hand side vector.</param> /// <param name="lhs">The left hand side vector. Also known as the result vector.</param> public void Approximate(Vector <double> rhs, Vector <double> lhs) { if (_decompositionLU == null) { throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); } if ((lhs.Count != rhs.Count) || (lhs.Count != _decompositionLU.RowCount)) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } // Solve: // Lz = y // Which gives // for (int i = 1; i < matrix.RowLength; i++) // { // z_i = l_ii^-1 * (y_i - SUM_(j<i) l_ij * z_j) // } // NOTE: l_ii should be 1 because u_ii has to be the value var rowValues = new DenseVector(_decompositionLU.RowCount); for (var i = 0; i < _decompositionLU.RowCount; i++) { // Clear the rowValues rowValues.Clear(); _decompositionLU.Row(i, rowValues); var sum = 0.0; for (var j = 0; j < i; j++) { sum += rowValues[j] * lhs[j]; } lhs[i] = rhs[i] - sum; } // Solve: // Ux = z // Which gives // for (int i = matrix.RowLength - 1; i > -1; i--) // { // x_i = u_ii^-1 * (z_i - SUM_(j > i) u_ij * x_j) // } for (var i = _decompositionLU.RowCount - 1; i > -1; i--) { _decompositionLU.Row(i, rowValues); var sum = 0.0; for (var j = _decompositionLU.RowCount - 1; j > i; j--) { sum += rowValues[j] * lhs[j]; } lhs[i] = 1 / rowValues[i] * (lhs[i] - sum); } }
/// <summary> /// Computes volatility scale for a given target. Equivalent to solving (or finding minimum if there is no solution) a quadratic. /// The scale is only applied to volatilities which has not been scaled already (towards another target). /// </summary> /// <param name="expiry"></param> /// <param name="tenor"></param> /// <param name="bound"></param> /// <param name="target"></param> /// <returns></returns> private double FindScale(int expiry, int tenor, double bound, double target) { int exp = expiry - 1; int ten = tenor - 1; double c0 = 0; double c1 = 0; double c2 = 0; double result; var tempVector1 = new DenseVector(_factors); var tempVector2 = new DenseVector(_factors); for (int i = 0; i <= exp; i++) { tempVector1.Clear(); tempVector2.Clear(); for (int j = 0; j <= ten; j++) { if (_isScaled[i][j + exp - i]) { tempVector1 = tempVector1 + _swaptionWeights.Get(expiry, tenor, j + 1) * _volatilities.Volatility[i].RowD(j + exp - i); } else { tempVector2 = tempVector2 + _swaptionWeights.Get(expiry, tenor, j + 1) * _volatilities.Volatility[i].RowD(j + exp - i); } } c0 += tempVector1 * tempVector1; c1 += tempVector1 * tempVector2; c2 += tempVector2 * tempVector2; } c1 = 2 * c1; c0 -= target * target * expiry; //quadratic discriminant double disc = c1 * c1 - 4 * c2 * c0; if (disc >= 0) { //find positive root, if exists result = (-c1 + Math.Sqrt(disc)) / (2 * c2); } else { //find minimum if no roots exist result = -c1 / (2 * c2); } if (result > bound) { result = bound; } else if (result < 1.0 / bound) { result = 1.0 / bound; } return(result); }
private double FindGamma(int exp, int ten, double bound, double target) { double c0 = 0; double c1 = 0; double c2 = 0; double result; var tempVector1 = new DenseVector(_param.NumberOfFactors); var tempVector2 = new DenseVector(_param.NumberOfFactors); var xi = _economy.Xi; double[][][] ai = _economy.Ai; for (int i = 0; i <= exp; i++) { tempVector1.Clear(); tempVector2.Clear(); for (int j = exp - i; j <= exp - i + ten; j++) { if (_isChanged[i][j]) { tempVector1 = tempVector1 + ai[exp][ten][j - exp + i] * xi[i].RowD(j); } else { tempVector2 = tempVector2 + ai[exp][ten][j - exp + i] * xi[i].RowD(j); } } c0 += tempVector1 * tempVector1; c1 += tempVector1 * tempVector2; c2 += tempVector2 * tempVector2; } c1 = 2 * c1; c0 -= target * target * (exp + 1); double disc = c1 * c1 - 4 * c2 * c0; if (disc >= 0) { result = (-c1 + System.Math.Sqrt(disc)) / (2 * c2); } else { result = -c1 / (2 * c2); } if (result > bound) { result = bound; } else if (result < 1.0 / bound) { result = 1.0 / bound; } return(result); }
public double CalculateByDropOut(ULDataBase X, bool DoB, bool DispB = false) { for (int k = 0; k < NX(0); k++) { MLUs[0].Z_lst[k] = X.gPara[k]; //Pointer copy is not good. Value copy. } foreach (var P in MLUs.Where(p => p.nxtMLU != null)) { //$$ ApplyDropout_____(P,DoB:DoB); P.Z_lst[0] = 1.0; var Q = P.nxtMLU; Q.U_lst = P.W_lst * P.Z_lst; Q.U_lst.Apply(Q.Z_lst, x => P.ActFunc(x)); //Activation Function } var Zout = MLUs.Last().Z_lst; double dt = Zout.Sum(); X.est = (dt <0.7 || dt> 1.5)? 99: Zout.MaximumIndex(); DenseVector E = new DenseVector(Nout); E.Clear(); if (X.ans >= 0 && X.ans <= 9) { E[X.ans] = 1.0; } DenseVector Edif = E - Zout; errorT = Edif * Edif; #region check if (DispB && X.ans != X.est && X.ID < 15) { int Nout = NSizeLst.Last(); Write($" {X.ID}"); for (int k = 0; k < Nout; k++) { Write($" {Zout[k]:0.00000}"); } WriteLine($" ->{Zout.MaximumIndex()} ans:{X.ans} est:{X.est} vMax:{Zout.Max():0.00000}"); } #endregion check return(errorT); }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient matrix, <c>A</c>.</param> /// <param name="input">The solution vector, <c>b</c></param> /// <param name="result">The result vector, <c>x</c></param> public void Solve(Matrix matrix, Vector input, Vector result) { // 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); } // Initialize the solver fields // Set the convergence monitor if (_iterator == null) { _iterator = Iterator.CreateDefault(); } if (_preconditioner == null) { _preconditioner = new UnitPreconditioner(); } _preconditioner.Initialize(matrix); // Choose an initial guess x_0 // Take x_0 = 0 Vector xtemp = new DenseVector(input.Count); // Choose k vectors q_1, q_2, ..., q_k // Build a new set if: // a) the stored set doesn't exist (i.e. == null) // b) Is of an incorrect length (i.e. too long) // c) The vectors are of an incorrect length (i.e. too long or too short) var useOld = false; if (_startingVectors != null) { // We don't accept collections with zero starting vectors so ... if (_startingVectors.Count <= NumberOfStartingVectorsToCreate(_numberOfStartingVectors, input.Count)) { // Only check the first vector for sizing. If that matches we assume the // other vectors match too. If they don't the process will crash if (_startingVectors[0].Count == input.Count) { useOld = true; } } } _startingVectors = useOld ? _startingVectors : CreateStartingVectors(_numberOfStartingVectors, input.Count); // Store the number of starting vectors. Not really necessary but easier to type :) var k = _startingVectors.Count; // r_0 = b - Ax_0 // This is basically a SAXPY so it could be made a lot faster Vector residuals = new DenseVector(matrix.RowCount); CalculateTrueResidual(matrix, residuals, xtemp, input); // Define the temporary values var c = new Complex[k]; // Define the temporary vectors Vector gtemp = new DenseVector(residuals.Count); Vector u = new DenseVector(residuals.Count); Vector utemp = new DenseVector(residuals.Count); Vector temp = new DenseVector(residuals.Count); Vector temp1 = new DenseVector(residuals.Count); Vector temp2 = new DenseVector(residuals.Count); Vector zd = new DenseVector(residuals.Count); Vector zg = new DenseVector(residuals.Count); Vector zw = new DenseVector(residuals.Count); var d = CreateVectorArray(_startingVectors.Count, residuals.Count); // g_0 = r_0 var g = CreateVectorArray(_startingVectors.Count, residuals.Count); residuals.CopyTo(g[k - 1]); var w = CreateVectorArray(_startingVectors.Count, residuals.Count); // FOR (j = 0, 1, 2 ....) var iterationNumber = 0; while (ShouldContinue(iterationNumber, xtemp, input, residuals)) { // SOLVE M g~_((j-1)k+k) = g_((j-1)k+k) _preconditioner.Approximate(g[k - 1], gtemp); // w_((j-1)k+k) = A g~_((j-1)k+k) matrix.Multiply(gtemp, w[k - 1]); // c_((j-1)k+k) = q^T_1 w_((j-1)k+k) c[k - 1] = _startingVectors[0].DotProduct(w[k - 1]); if (c[k - 1].Real.AlmostEqual(0, 1) && c[k - 1].Imaginary.AlmostEqual(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // alpha_(jk+1) = q^T_1 r_((j-1)k+k) / c_((j-1)k+k) var alpha = _startingVectors[0].DotProduct(residuals) / c[k - 1]; // u_(jk+1) = r_((j-1)k+k) - alpha_(jk+1) w_((j-1)k+k) w[k - 1].Multiply(-alpha, temp); residuals.Add(temp, u); // SOLVE M u~_(jk+1) = u_(jk+1) _preconditioner.Approximate(u, temp1); temp1.CopyTo(utemp); // rho_(j+1) = -u^t_(jk+1) A u~_(jk+1) / ||A u~_(jk+1)||^2 matrix.Multiply(temp1, temp); var rho = temp.DotProduct(temp); // If rho is zero then temp is a zero vector and we're probably // about to have zero residuals (i.e. an exact solution). // So set rho to 1.0 because in the next step it will turn to zero. if (rho.Real.AlmostEqual(0, 1) && rho.Imaginary.AlmostEqual(0, 1)) { rho = 1.0; } rho = -u.DotProduct(temp) / rho; // r_(jk+1) = rho_(j+1) A u~_(jk+1) + u_(jk+1) u.CopyTo(residuals); // Reuse temp temp.Multiply(rho, temp); residuals.Add(temp, temp2); temp2.CopyTo(residuals); // x_(jk+1) = x_((j-1)k_k) - rho_(j+1) u~_(jk+1) + alpha_(jk+1) g~_((j-1)k+k) utemp.Multiply(-rho, temp); xtemp.Add(temp, temp2); temp2.CopyTo(xtemp); gtemp.Multiply(alpha, gtemp); xtemp.Add(gtemp, temp2); temp2.CopyTo(xtemp); // Check convergence and stop if we are converged. if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) { // Calculate the true residual CalculateTrueResidual(matrix, residuals, xtemp, input); // Now recheck the convergence if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) { // We're all good now. // Exit from the while loop. break; } } // FOR (i = 1,2, ...., k) for (var i = 0; i < k; i++) { // z_d = u_(jk+1) u.CopyTo(zd); // z_g = r_(jk+i) residuals.CopyTo(zg); // z_w = 0 zw.Clear(); // FOR (s = i, ...., k-1) AND j >= 1 Complex beta; if (iterationNumber >= 1) { for (var s = i; s < k - 1; s++) { // beta^(jk+i)_((j-1)k+s) = -q^t_(s+1) z_d / c_((j-1)k+s) beta = -_startingVectors[s + 1].DotProduct(zd) / c[s]; // z_d = z_d + beta^(jk+i)_((j-1)k+s) d_((j-1)k+s) d[s].Multiply(beta, temp); zd.Add(temp, temp2); temp2.CopyTo(zd); // z_g = z_g + beta^(jk+i)_((j-1)k+s) g_((j-1)k+s) g[s].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); // z_w = z_w + beta^(jk+i)_((j-1)k+s) w_((j-1)k+s) w[s].Multiply(beta, temp); zw.Add(temp, temp2); temp2.CopyTo(zw); } } beta = rho * c[k - 1]; if (beta.Real.AlmostEqual(0, 1) && beta.Imaginary.AlmostEqual(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // beta^(jk+i)_((j-1)k+k) = -(q^T_1 (r_(jk+1) + rho_(j+1) z_w)) / (rho_(j+1) c_((j-1)k+k)) zw.Multiply(rho, temp2); residuals.Add(temp2, temp); beta = -_startingVectors[0].DotProduct(temp) / beta; // z_g = z_g + beta^(jk+i)_((j-1)k+k) g_((j-1)k+k) g[k - 1].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); // z_w = rho_(j+1) (z_w + beta^(jk+i)_((j-1)k+k) w_((j-1)k+k)) w[k - 1].Multiply(beta, temp); zw.Add(temp, temp2); temp2.CopyTo(zw); zw.Multiply(rho, zw); // z_d = r_(jk+i) + z_w residuals.Add(zw, zd); // FOR (s = 1, ... i - 1) for (var s = 0; s < i - 1; s++) { // beta^(jk+i)_(jk+s) = -q^T_s+1 z_d / c_(jk+s) beta = -_startingVectors[s + 1].DotProduct(zd) / c[s]; // z_d = z_d + beta^(jk+i)_(jk+s) * d_(jk+s) d[s].Multiply(beta, temp); zd.Add(temp, temp2); temp2.CopyTo(zd); // z_g = z_g + beta^(jk+i)_(jk+s) * g_(jk+s) g[s].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); } // d_(jk+i) = z_d - u_(jk+i) zd.Subtract(u, d[i]); // g_(jk+i) = z_g + z_w zg.Add(zw, g[i]); // IF (i < k - 1) if (i < k - 1) { // c_(jk+1) = q^T_i+1 d_(jk+i) c[i] = _startingVectors[i + 1].DotProduct(d[i]); if (c[i].Real.AlmostEqual(0, 1) && c[i].Imaginary.AlmostEqual(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // alpha_(jk+i+1) = q^T_(i+1) u_(jk+i) / c_(jk+i) alpha = _startingVectors[i + 1].DotProduct(u) / c[i]; // u_(jk+i+1) = u_(jk+i) - alpha_(jk+i+1) d_(jk+i) d[i].Multiply(-alpha, temp); u.Add(temp, temp2); temp2.CopyTo(u); // SOLVE M g~_(jk+i) = g_(jk+i) _preconditioner.Approximate(g[i], gtemp); // x_(jk+i+1) = x_(jk+i) + rho_(j+1) alpha_(jk+i+1) g~_(jk+i) gtemp.Multiply(rho * alpha, temp); xtemp.Add(temp, temp2); temp2.CopyTo(xtemp); // w_(jk+i) = A g~_(jk+i) matrix.Multiply(gtemp, w[i]); // r_(jk+i+1) = r_(jk+i) - rho_(j+1) alpha_(jk+i+1) w_(jk+i) w[i].Multiply(-rho * alpha, temp); residuals.Add(temp, temp2); temp2.CopyTo(residuals); // We can check the residuals here if they're close if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) { // Recalculate the residuals and go round again. This is done to ensure that // we have the proper residuals. CalculateTrueResidual(matrix, residuals, xtemp, input); } } } // END ITERATION OVER i iterationNumber++; } // copy the temporary result to the real result vector xtemp.CopyTo(result); }
/// <summary> /// Approximates the solution to the matrix equation <b>Ax = b</b>. /// </summary> /// <param name="rhs">The right hand side vector.</param> /// <param name="lhs">The left hand side vector. Also known as the result vector.</param> public void Approximate(Vector rhs, Vector lhs) { if (rhs == null) { throw new ArgumentNullException("rhs"); } if (lhs == null) { throw new ArgumentNullException("lhs"); } if (_decompositionLU == null) { throw new ArgumentException(Resources.ArgumentMatrixDoesNotExist); } if ((lhs.Count != rhs.Count) || (lhs.Count != _decompositionLU.RowCount)) { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } // Solve: // Lz = y // Which gives // for (int i = 1; i < matrix.RowLength; i++) // { // z_i = l_ii^-1 * (y_i - SUM_(j<i) l_ij * z_j) // } // NOTE: l_ii should be 1 because u_ii has to be the value Vector rowValues = new DenseVector(_decompositionLU.RowCount); for (var i = 0; i < _decompositionLU.RowCount; i++) { // Clear the rowValues rowValues.Clear(); _decompositionLU.Row(i, rowValues); var sum = 0.0; for (var j = 0; j < i; j++) { sum += rowValues[j] * lhs[j]; } lhs[i] = rhs[i] - sum; } // Solve: // Ux = z // Which gives // for (int i = matrix.RowLength - 1; i > -1; i--) // { // x_i = u_ii^-1 * (z_i - SUM_(j > i) u_ij * x_j) // } for (var i = _decompositionLU.RowCount - 1; i > -1; i--) { _decompositionLU.Row(i, rowValues); var sum = 0.0; for (var j = _decompositionLU.RowCount - 1; j > i; j--) { sum += rowValues[j] * lhs[j]; } lhs[i] = 1 / rowValues[i] * (lhs[i] - sum); } }
/// <summary> /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the /// solution vector and x is the unknown vector. /// </summary> /// <param name="matrix">The coefficient matrix, <c>A</c>.</param> /// <param name="input">The solution vector, <c>b</c></param> /// <param name="result">The result vector, <c>x</c></param> public void Solve(Matrix matrix, Vector input, Vector result) { // 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); } if (input.Count != matrix.RowCount) { throw new ArgumentException(Resources.ArgumentMatrixDimensions); } // Initialize the solver fields // Set the convergence monitor if (_iterator == null) { _iterator = Iterator.CreateDefault(); } if (_preconditioner == null) { _preconditioner = new UnitPreconditioner(); } _preconditioner.Initialize(matrix); // Choose an initial guess x_0 // Take x_0 = 0 Vector xtemp = new DenseVector(input.Count); // Choose k vectors q_1, q_2, ..., q_k // Build a new set if: // a) the stored set doesn't exist (i.e. == null) // b) Is of an incorrect length (i.e. too long) // c) The vectors are of an incorrect length (i.e. too long or too short) var useOld = false; if (_startingVectors != null) { // We don't accept collections with zero starting vectors so ... if (_startingVectors.Count <= NumberOfStartingVectorsToCreate(_numberOfStartingVectors, input.Count)) { // Only check the first vector for sizing. If that matches we assume the // other vectors match too. If they don't the process will crash if (_startingVectors[0].Count == input.Count) { useOld = true; } } } _startingVectors = useOld ? _startingVectors : CreateStartingVectors(_numberOfStartingVectors, input.Count); // Store the number of starting vectors. Not really necessary but easier to type :) var k = _startingVectors.Count; // r_0 = b - Ax_0 // This is basically a SAXPY so it could be made a lot faster Vector residuals = new DenseVector(matrix.RowCount); CalculateTrueResidual(matrix, residuals, xtemp, input); // Define the temporary values var c = new Complex[k]; // Define the temporary vectors Vector gtemp = new DenseVector(residuals.Count); Vector u = new DenseVector(residuals.Count); Vector utemp = new DenseVector(residuals.Count); Vector temp = new DenseVector(residuals.Count); Vector temp1 = new DenseVector(residuals.Count); Vector temp2 = new DenseVector(residuals.Count); Vector zd = new DenseVector(residuals.Count); Vector zg = new DenseVector(residuals.Count); Vector zw = new DenseVector(residuals.Count); var d = CreateVectorArray(_startingVectors.Count, residuals.Count); // g_0 = r_0 var g = CreateVectorArray(_startingVectors.Count, residuals.Count); residuals.CopyTo(g[k - 1]); var w = CreateVectorArray(_startingVectors.Count, residuals.Count); // FOR (j = 0, 1, 2 ....) var iterationNumber = 0; while (ShouldContinue(iterationNumber, xtemp, input, residuals)) { // SOLVE M g~_((j-1)k+k) = g_((j-1)k+k) _preconditioner.Approximate(g[k - 1], gtemp); // w_((j-1)k+k) = A g~_((j-1)k+k) matrix.Multiply(gtemp, w[k - 1]); // c_((j-1)k+k) = q^T_1 w_((j-1)k+k) c[k - 1] = _startingVectors[0].DotProduct(w[k - 1]); if (c[k - 1].Real.AlmostEqual(0, 1) && c[k - 1].Imaginary.AlmostEqual(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // alpha_(jk+1) = q^T_1 r_((j-1)k+k) / c_((j-1)k+k) var alpha = _startingVectors[0].DotProduct(residuals) / c[k - 1]; // u_(jk+1) = r_((j-1)k+k) - alpha_(jk+1) w_((j-1)k+k) w[k - 1].Multiply(-alpha, temp); residuals.Add(temp, u); // SOLVE M u~_(jk+1) = u_(jk+1) _preconditioner.Approximate(u, temp1); temp1.CopyTo(utemp); // rho_(j+1) = -u^t_(jk+1) A u~_(jk+1) / ||A u~_(jk+1)||^2 matrix.Multiply(temp1, temp); var rho = temp.DotProduct(temp); // If rho is zero then temp is a zero vector and we're probably // about to have zero residuals (i.e. an exact solution). // So set rho to 1.0 because in the next step it will turn to zero. if (rho.Real.AlmostEqual(0, 1) && rho.Imaginary.AlmostEqual(0, 1)) { rho = 1.0; } rho = -u.DotProduct(temp) / rho; // r_(jk+1) = rho_(j+1) A u~_(jk+1) + u_(jk+1) u.CopyTo(residuals); // Reuse temp temp.Multiply(rho, temp); residuals.Add(temp, temp2); temp2.CopyTo(residuals); // x_(jk+1) = x_((j-1)k_k) - rho_(j+1) u~_(jk+1) + alpha_(jk+1) g~_((j-1)k+k) utemp.Multiply(-rho, temp); xtemp.Add(temp, temp2); temp2.CopyTo(xtemp); gtemp.Multiply(alpha, gtemp); xtemp.Add(gtemp, temp2); temp2.CopyTo(xtemp); // Check convergence and stop if we are converged. if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) { // Calculate the true residual CalculateTrueResidual(matrix, residuals, xtemp, input); // Now recheck the convergence if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) { // We're all good now. // Exit from the while loop. break; } } // FOR (i = 1,2, ...., k) for (var i = 0; i < k; i++) { // z_d = u_(jk+1) u.CopyTo(zd); // z_g = r_(jk+i) residuals.CopyTo(zg); // z_w = 0 zw.Clear(); // FOR (s = i, ...., k-1) AND j >= 1 Complex beta; if (iterationNumber >= 1) { for (var s = i; s < k - 1; s++) { // beta^(jk+i)_((j-1)k+s) = -q^t_(s+1) z_d / c_((j-1)k+s) beta = -_startingVectors[s + 1].DotProduct(zd) / c[s]; // z_d = z_d + beta^(jk+i)_((j-1)k+s) d_((j-1)k+s) d[s].Multiply(beta, temp); zd.Add(temp, temp2); temp2.CopyTo(zd); // z_g = z_g + beta^(jk+i)_((j-1)k+s) g_((j-1)k+s) g[s].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); // z_w = z_w + beta^(jk+i)_((j-1)k+s) w_((j-1)k+s) w[s].Multiply(beta, temp); zw.Add(temp, temp2); temp2.CopyTo(zw); } } beta = rho * c[k - 1]; if (beta.Real.AlmostEqual(0, 1) && beta.Imaginary.AlmostEqual(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // beta^(jk+i)_((j-1)k+k) = -(q^T_1 (r_(jk+1) + rho_(j+1) z_w)) / (rho_(j+1) c_((j-1)k+k)) zw.Multiply(rho, temp2); residuals.Add(temp2, temp); beta = -_startingVectors[0].DotProduct(temp) / beta; // z_g = z_g + beta^(jk+i)_((j-1)k+k) g_((j-1)k+k) g[k - 1].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); // z_w = rho_(j+1) (z_w + beta^(jk+i)_((j-1)k+k) w_((j-1)k+k)) w[k - 1].Multiply(beta, temp); zw.Add(temp, temp2); temp2.CopyTo(zw); zw.Multiply(rho, zw); // z_d = r_(jk+i) + z_w residuals.Add(zw, zd); // FOR (s = 1, ... i - 1) for (var s = 0; s < i - 1; s++) { // beta^(jk+i)_(jk+s) = -q^T_s+1 z_d / c_(jk+s) beta = -_startingVectors[s + 1].DotProduct(zd) / c[s]; // z_d = z_d + beta^(jk+i)_(jk+s) * d_(jk+s) d[s].Multiply(beta, temp); zd.Add(temp, temp2); temp2.CopyTo(zd); // z_g = z_g + beta^(jk+i)_(jk+s) * g_(jk+s) g[s].Multiply(beta, temp); zg.Add(temp, temp2); temp2.CopyTo(zg); } // d_(jk+i) = z_d - u_(jk+i) zd.Subtract(u, d[i]); // g_(jk+i) = z_g + z_w zg.Add(zw, g[i]); // IF (i < k - 1) if (i < k - 1) { // c_(jk+1) = q^T_i+1 d_(jk+i) c[i] = _startingVectors[i + 1].DotProduct(d[i]); if (c[i].Real.AlmostEqual(0, 1) && c[i].Imaginary.AlmostEqual(0, 1)) { throw new Exception("Iterative solver experience a numerical break down"); } // alpha_(jk+i+1) = q^T_(i+1) u_(jk+i) / c_(jk+i) alpha = _startingVectors[i + 1].DotProduct(u) / c[i]; // u_(jk+i+1) = u_(jk+i) - alpha_(jk+i+1) d_(jk+i) d[i].Multiply(-alpha, temp); u.Add(temp, temp2); temp2.CopyTo(u); // SOLVE M g~_(jk+i) = g_(jk+i) _preconditioner.Approximate(g[i], gtemp); // x_(jk+i+1) = x_(jk+i) + rho_(j+1) alpha_(jk+i+1) g~_(jk+i) gtemp.Multiply(rho * alpha, temp); xtemp.Add(temp, temp2); temp2.CopyTo(xtemp); // w_(jk+i) = A g~_(jk+i) matrix.Multiply(gtemp, w[i]); // r_(jk+i+1) = r_(jk+i) - rho_(j+1) alpha_(jk+i+1) w_(jk+i) w[i].Multiply(-rho * alpha, temp); residuals.Add(temp, temp2); temp2.CopyTo(residuals); // We can check the residuals here if they're close if (!ShouldContinue(iterationNumber, xtemp, input, residuals)) { // Recalculate the residuals and go round again. This is done to ensure that // we have the proper residuals. CalculateTrueResidual(matrix, residuals, xtemp, input); } } } // END ITERATION OVER i iterationNumber++; } // copy the temporary result to the real result vector xtemp.CopyTo(result); }