Beispiel #1
0
        /// <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);
            }
        }
Beispiel #2
0
        /// <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);
            }
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
            }
        }
Beispiel #8
0
        /// <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);
        }