public override IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs,
                                                  IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer)
        {
            //TODO: find a better way to handle optimizations for the case x0=0, than using an initialGuessIsZero flag
            Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length);
            Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length);

            this.Matrix         = matrix;
            this.Preconditioner = preconditioner;
            this.Rhs            = rhs;

            // Initial solution and rhs (r = b - A * x)
            this.solution = solution;
            if (ReorthoCache.Directions.Count > 0)
            {
                if (!initialGuessIsZero)
                {
                    solution.Clear();
                }
                CalculateInitialSolutionFromStoredDirections(rhs, solution);
                residual = ExactResidual.Calculate(matrix, rhs, solution);
            }
            else             // preferably call base method
            {
                // r = b - A * x
                if (initialGuessIsZero)
                {
                    residual = rhs.Copy();
                }
                else
                {
                    residual = ExactResidual.Calculate(matrix, rhs, solution);
                }
            }

            // Initialize vectors
            //TODO: Pehaps I can just clear them from previous iterations
            precondResidual      = zeroVectorInitializer();
            direction            = zeroVectorInitializer();
            matrixTimesDirection = zeroVectorInitializer();

            int maxIterations = MaxIterationsProvider.GetMaxIterations(matrix.NumColumns);

            return(SolveInternal(maxIterations, zeroVectorInitializer));
        }
        /// <summary>
        /// Solves the linear system A * x = b by solving the preconditioned system inv(P) * A * inv(P)^T * y = inv(P) * b,
        /// where A = <paramref name="matrix"/>, b = <paramref name="rhsVector"/>, x is the solution, y = P^T * x,
        /// P*P^T = <paramref name="preconditioner"/>.
        /// Initially x = <paramref name="initialGuess"/> and then it converges to the solution.
        /// </summary>
        /// <param name="matrix">
        /// Represents the matrix A of the linear system A * x = b, which must be symmetric positive definite.
        /// </param>
        /// <param name="rhs">
        /// The right hand side vector b of the linear system A * x = b. Constraints:
        /// <paramref name="rhs"/>.<see cref="IIndexable1D.Length"/>
        /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumRows"/>.
        /// </param>
        /// <param name="preconditioner">
        /// A preconditioner matrix that is also symmetric positive definite and has the same dimensions as A.
        /// </param>
        /// <param name="solution">
        /// The vector from which to start refining the solution vector x. Constraints:
        /// <paramref name="solution"/>.<see cref="IIndexable1D.Length"/>
        /// == <paramref name="matrix"/>.<see cref="IIndexable2D.NumColumns"/>.
        /// </param>
        /// <param name="initialGuessIsZero">
        /// If <paramref name="solution"/> is 0, then set <paramref name="initialGuessIsZero"/> to true to avoid performing the
        /// operation b-A*0 before starting.
        /// </param>
        /// <exception cref="NonMatchingDimensionsException">
        /// Thrown if <paramref name="rhs"/> or <paramref name="solution"/> violate the described constraints.
        /// </exception>
        public virtual IterativeStatistics Solve(ILinearTransformation matrix, IPreconditioner preconditioner, IVectorView rhs,
                                                 IVector solution, bool initialGuessIsZero, Func <IVector> zeroVectorInitializer)
        {
            //TODO: find a better way to handle optimizations for the case x0=0, than using an initialGuessIsZero flag

            Preconditions.CheckMultiplicationDimensions(matrix.NumColumns, solution.Length);
            Preconditions.CheckSystemSolutionDimensions(matrix.NumRows, rhs.Length);

            this.Matrix         = matrix;
            this.Preconditioner = preconditioner;
            this.Rhs            = rhs;
            this.solution       = solution;

            // r = b - A * x
            if (initialGuessIsZero)
            {
                residual = rhs.Copy();
            }
            else
            {
                residual = ExactResidual.Calculate(matrix, rhs, solution);
            }
            return(SolveInternal(MaxIterationsProvider.GetMaxIterations(matrix.NumColumns), zeroVectorInitializer));
        }