private static void TestGetSubmatrix()
        {
            // These are useful for debugging
            //string outputPath = @"C:\Users\Serafeim\Desktop\output.txt";
            //var writer = new LinearAlgebra.Output.FullMatrixWriter();

            var matrix = Matrix.CreateFromArray(
                MultiDiagonalMatrices.CreateSymmetricPosDef(100, new int[] { 2, 4, 8, 16, 32, 64 }));
            var matrixSky = SkylineMatrix.CreateFromMatrix(matrix);

            var indices     = new int[] { 0, 2, 4, 6, 12, 24, 32, 50, 64, 80 };
            var indicesPerm = new int[] { 32, 80, 64, 0, 12, 24, 6, 50, 4, 2 };

            int[] rowIndices = indicesPerm;
            var   colIndices = new int[] { 90, 10, 20, 60, 40, 50, 0, 70, 80, 30 };

            Matrix        subMatrixFull = matrixSky.GetSubmatrixSymmetricFull(indices);
            SkylineMatrix subMatrixSky  = matrixSky.GetSubmatrixSymmetricSkyline(indices);
            //writer.WriteToFile(subMatrixSky, outputPath, true);
            CscMatrix subMatrixCsc = matrixSky.GetSubmatrixCsc(indices, indices);

            Matrix        subMatrixPermFull = matrixSky.GetSubmatrixSymmetricFull(indicesPerm);
            SkylineMatrix subMatrixPermSky  = matrixSky.GetSubmatrixSymmetricSkyline(indicesPerm);
            CscMatrix     subMatrixPermCsc  = matrixSky.GetSubmatrixCsc(indicesPerm, indicesPerm);

            CscMatrix subMatrixRectCsc = matrixSky.GetSubmatrixCsc(rowIndices, colIndices);

            Matrix subMatrixExpected = matrix.GetSubmatrix(indices, indices);

            //writer.WriteToFile(subMatrixExpected, outputPath, true);
            Assert.True(subMatrixExpected.Equals(subMatrixFull));
            Assert.True(subMatrixExpected.Equals(subMatrixSky));
            Assert.True(subMatrixExpected.Equals(subMatrixCsc));

            Matrix subMatrixPermExpected = matrix.GetSubmatrix(indicesPerm, indicesPerm);

            Assert.True(subMatrixPermExpected.Equals(subMatrixPermFull));
            Assert.True(subMatrixPermExpected.Equals(subMatrixPermSky));
            Assert.True(subMatrixPermExpected.Equals(subMatrixPermCsc));

            Matrix subMatrixRectExpected = matrix.GetSubmatrix(rowIndices, colIndices);

            Assert.True(subMatrixRectExpected.Equals(subMatrixRectCsc));
        }
        //[Fact]
        private static void InvestigateNoiseStagnation()
        {
            double noiseWidth = 100;

            int order = 100;
            //var A = Matrix.CreateFromArray(MultiDiagonalMatrices.CreateSymmetric(order, new int[] { 0, 1, 5, 7, 12 }));
            var valueOfEachDiagonal = new Dictionary <int, double>();

            valueOfEachDiagonal[0] = 10.0;
            valueOfEachDiagonal[1] = 4.0;
            valueOfEachDiagonal[5] = 3.0;
            var A = Matrix.CreateFromArray(MultiDiagonalMatrices.CreateSymmetric(order, valueOfEachDiagonal));
            var M = new IdentityPreconditioner();
            //var M = new JacobiPreconditioner(A.GetDiagonalAsArray());

            // Method A: Regular PCG
            var pcgBuilder = new PcgAlgorithm.Builder();

            pcgBuilder.ResidualTolerance     = 1E-15;
            pcgBuilder.MaxIterationsProvider = new FixedMaxIterationsProvider(50);
            var pcg = pcgBuilder.Build();

            // Method B: Reorthogonalized PCG, but without keeping direction vectors from previous solutions.
            var pcgReorthoRestartBuilder = new ReorthogonalizedPcg.Builder();

            pcgReorthoRestartBuilder.ResidualTolerance     = 1E-15;
            pcgReorthoRestartBuilder.MaxIterationsProvider = new FixedMaxIterationsProvider(50);
            var pcgReorthoRestart = pcgReorthoRestartBuilder.Build();

            // Method C: Reorthogonalized PCG, where the second solution will reuse direction vectors from the first
            var pcgReorthoBuilder = new ReorthogonalizedPcg.Builder();

            pcgReorthoBuilder.ResidualTolerance     = 1E-15;
            pcgReorthoBuilder.MaxIterationsProvider = new FixedMaxIterationsProvider(50);
            var pcgReortho = pcgReorthoBuilder.Build();

            // Initial rhs
            Vector x0         = Vector.CreateWithValue(order, 1);
            Vector x0Expected = x0.Copy();
            Vector b0         = A * x0Expected;

            Vector xA = Vector.CreateZero(A.NumRows);
            IterativeStatistics statsA = pcg.Solve(A, M, b0, xA, true, () => Vector.CreateZero(order));

            Debug.WriteLine($"Initial run - method A: iterations = {statsA.NumIterationsRequired}");

            Vector xB = Vector.CreateZero(A.NumRows);
            IterativeStatistics statsB = pcgReorthoRestart.Solve(A, M, b0, xB, true, () => Vector.CreateZero(order));

            Debug.WriteLine($"Initial run - method B iterations = {statsB.NumIterationsRequired}");

            Vector xC = Vector.CreateZero(A.NumRows);
            IterativeStatistics statsC = pcgReortho.Solve(A, M, b0, xC, true, () => Vector.CreateZero(order));

            Debug.WriteLine($"Initial run - method C: iterations = {statsC.NumIterationsRequired}");

            // Perturbed rhs
            int    seed = 345;
            Vector dx   = Vector.CreateFromArray(RandomMatrices.CreateRandomVector(order, seed));

            Vector x1Expected = x0 + noiseWidth * dx;
            Vector b1         = A * x1Expected;

            xA     = Vector.CreateZero(A.NumRows);
            statsA = pcg.Solve(A, M, b1, xA, true, () => Vector.CreateZero(order));
            Debug.WriteLine($"2nd run, noise = {noiseWidth} - method A: iterations = {statsA.NumIterationsRequired}");

            xB = Vector.CreateZero(A.NumRows);
            pcgReorthoRestart.ReorthoCache.Clear();
            statsB = pcgReorthoRestart.Solve(A, M, b1, xB, true, () => Vector.CreateZero(order));
            Debug.WriteLine($"2nd run, noise = {noiseWidth} - method B iterations = {statsB.NumIterationsRequired}");

            xC     = Vector.CreateZero(A.NumRows);
            statsC = pcgReortho.Solve(A, M, b1, xC, true, () => Vector.CreateZero(order));
            Debug.WriteLine($"2nd run, noise = {noiseWidth} - method C: iterations = {statsC.NumIterationsRequired}");
        }