public void minusTest()
        {
            const int N = 50;
            var       A = SparseDoubleMatrix.Identity(N, N);

            for (int i = 0; i < N; i++)
            {
                A[i, i] = i % 5 == 0 ? 1.0 : 0.0;
            }
            var A1    = A.Clone();
            var Zeros = SparseDoubleMatrix.Identity(N, N);

            for (int i = 0; i < N; i++)
            {
                Zeros[i, i] = 0.0;
            }

            var B = SparseDoubleMatrix.Identity(N, N);

            for (int i = 0; i < N; i++)
            {
                B[i, i] = i % 5 == 0 ? 1.0 : 0.0;
            }

            var C = A.minus(B);

            AssertMatrixEqualsEps(C, Zeros);
            C = A - B;
            AssertMatrixEqualsEps(C, Zeros);
        }
        public void MapTest1()
        {
            int N = 6;

            var m1 = new SparseDoubleMatrix(N, N);
            var m2 = new SparseDoubleMatrix(N, N);

            // Fill matrix m2 diagonal elements with 66
            m1.MapSparseIncludingDiagonal((a, r, c) => a + (r == c ? 66 : 0), m2);

            for (int i = 0; i < m2.RowCount; ++i)
            {
                for (int j = 0; j < m2.ColumnCount; ++j)
                {
                    Assert.AreEqual(i == j ? 66 : 0, m2[i, j]);
                }
            }

            // the same should work with the now already used matrix
            // fill diagonal now with 77
            m1.MapSparseIncludingDiagonal((a, r, c) => a + (r == c ? 77 : 0), m2);

            for (int i = 0; i < m2.RowCount; ++i)
            {
                for (int j = 0; j < m2.ColumnCount; ++j)
                {
                    Assert.AreEqual(i == j ? 77 : 0, m2[i, j]);
                }
            }
        }
        public void TimesTest()
        {
            const int N = 50;
            const int M = 30;
            var       A = SparseDoubleMatrix.Identity(M, N);

            for (int i = 0; i < M; i++)
            {
                if (i < N)
                {
                    A[i, i] = i % 5 == 0 ? 1.0 : 0.0;
                }
            }

            var b = new DoubleVector(N);

            for (int i = 0; i < N; i++)
            {
                b[i] = 2.0;
            }

            var B = new DoubleVector(M);

            for (int i = 0; i < M; i++)
            {
                B[i] = i % 5 == 0 ? 2.0 : 0.0;
            }

            var C = A.times(b);

            AssertVectorEqualsEps(B, C);
        }
Exemple #4
0
        /// <summary>Solves system of linear equations Ax = b using Gaussian elimination with partial pivoting</summary>
        /// <param name="A">Sparse matrix, 'A'. This matrix is modified during solution!</param>
        /// <param name="b">Right part, 'b', is modified during solution.</param>
        /// <returns>Vector x with the result.</returns>
        public double[] SolveDestructive(SparseDoubleMatrix A, double[] b)
        {
            var x = new double[b.Length];

            SolveDestructive(A, b, x);
            return(x);
        }
Exemple #5
0
        /// <summary>Matrix subtraction for a sparse matrix</summary>
        /// <param name="B">The matrix to subtract</param>
        /// <returns>The result A - B</returns>
        public SparseDoubleMatrix minus(SparseDoubleMatrix B)
        {
            if (B == null)
            {
                throw new ArgumentNullException("B");
            }
            var C = new SparseDoubleMatrix(m, n);

            for (int i = 0; i < m; i++)
            {
                if (indices[i] != null)
                {
                    C.indices[i] = new int[count[i]];
                    C.items[i]   = new double[count[i]];
                    for (int j = 0; j < count[i]; j++)
                    {
                        C.indices[i][j] = indices[i][j];
                        C.items[i][j]   = items[i][j] - B.items[i][j];
                    }
                }
                C.count[i] = count[i];
            }

            return(C);
        }
        public void MapTest5()
        {
            int N = 6;

            var m1 = new SparseDoubleMatrix(N, N);
            var m2 = new SparseDoubleMatrix(N, N);

            // Pre-fill m1 elements right of the diagonal with values
            for (int i = 0; i < N - 1; ++i)
            {
                m1[i, i + 1] = i * 13;
            }

            // Fill matrix m2 diagonal elements with 66
            m1.MapSparseIncludingDiagonal((a, r, c) => 3 * a + (r == c ? 66 : 0), m2);

            for (int i = 0; i < m2.RowCount; ++i)
            {
                for (int j = 0; j < m2.ColumnCount; ++j)
                {
                    double expected = 0;
                    if (i == j)
                    {
                        expected = 66;
                    }
                    else if (i + 1 == j)
                    {
                        expected = i * 13 * 3;
                    }
                    Assert.AreEqual(expected, m2[i, j]);
                }
            }

            // the same should work with the now already used matrix
            // fill diagonal now with 77
            m1.MapSparseIncludingDiagonal((a, r, c) => 5 * a + (r == c ? 77 : 0), m2);

            for (int i = 0; i < m2.RowCount; ++i)
            {
                for (int j = 0; j < m2.ColumnCount; ++j)
                {
                    double expected = 0;
                    if (i == j)
                    {
                        expected = 77;
                    }
                    else if (i + 1 == j)
                    {
                        expected = i * 13 * 5;
                    }
                    Assert.AreEqual(expected, m2[i, j]);
                }
            }
        }
        public void SolveGETest()
        {
            const int N = 50;
            var       a = new SparseDoubleMatrix(N, N);

            for (int i = 0; i < N; i++)
            {
                a[i, i] = 1;
            }
            // Apply random rotations around each pair of axes. This will keep det(A) ~ 1
            var rand = new Random();

            for (int i = 0; i < N; i++)
            {
                for (int j = i + 1; j < N; j++)
                {
                    double angle = rand.NextDouble() * 2 * Math.PI;
                    var    r     = new SparseDoubleMatrix(N, N);
                    for (int k = 0; k < N; k++)
                    {
                        r[k, k] = 1;
                    }
                    r[i, i] = r[j, j] = Math.Cos(angle);
                    r[i, j] = Math.Sin(angle);
                    r[j, i] = -Math.Sin(angle);
                    a       = a * r;
                }
            }

            var ainit = a.Clone();
            // Generate random vector
            var b = new DoubleVector(N);

            for (int i = 0; i < N; i++)
            {
                b[i] = rand.NextDouble();
            }

            var binit = b.Clone();
            // Solve system
            var solver = new GaussianEliminationSolver();
            var sw     = new Stopwatch();

            sw.Start();
            var x = solver.SolveDestructive(a, b.GetInternalData());

            sw.Stop();
            Trace.WriteLine("Gaussian elimination took: " + sw.ElapsedTicks);
            // Put solution into system
            var b2 = ainit * x;

            // Verify result is the same
            Assert.IsTrue(VectorMath.LInfinityNorm(binit, b2) < 1e-6);
        }
Exemple #8
0
        public SparseDoubleMatrix Clone()
        {
            var A = new SparseDoubleMatrix(m, n);

            for (int i = 0; i < m; i++)
            {
                A.indices[i] = (int[])indices[i].Clone();
                A.items[i]   = (double[])items[i].Clone();
                A.count      = (int[])count.Clone();
            }
            return(A);
        }
        private void AssertMatrixEqualsEps(SparseDoubleMatrix A, SparseDoubleMatrix B)
        {
            double sum = 0.0;

            for (int i = 0; i < A.RowCount; i++)
            {
                for (int j = 0; j < A.ColumnCount; j++)
                {
                    sum += A[i, j] - B[i, j];
                }
            }

            AssertEqualsEps(sum, 0.0);
        }
        public void isLowerTriangularTest()
        {
            const int N = 50;
            var       A = SparseDoubleMatrix.Identity(N, N);

            for (int i = 0; i < N; i++)
            {
                A[i, i] = i % 5 == 0 ? 1.0 : 0.0;
            }

            Assert.AreEqual(A.IsLowerTriangular(), true);
            A[45, 40] = 1.0;
            Assert.AreEqual(A.IsLowerTriangular(), true);
            A[40, 45] = 1.0;
            Assert.AreEqual(A.IsLowerTriangular(), false);
        }
Exemple #11
0
        /// <summary>Matrix multiplication by a scalar</summary>
        /// <param name="s">Scalar</param>
        /// <returns>Scaled sparse matrix</returns>
        public SparseDoubleMatrix times(double s)
        {
            var B = new SparseDoubleMatrix(m, n);

            for (int i = 0; i < m; i++)
            {
                if (indices[i] != null)
                {
                    B.indices[i] = new int[count[i]];
                    B.items[i]   = new double[count[i]];
                    for (int j = 0; j < count[i]; j++)
                    {
                        B.indices[i][j] = indices[i][j];
                        B.items[i][j]   = s * items[i][j];
                    }
                }
                B.count[i] = count[i];
            }
            return(B);
        }
Exemple #12
0
        /// <summary>Matrix right multiplication by a matrix</summary>
        /// <param name="B">Scaling factor</param>
        /// <returns>A * B where A is current sparce matrix</returns>
        public SparseDoubleMatrix times(SparseDoubleMatrix B)
        {
            if (B == null)
            {
                throw new ArgumentNullException("B");
            }
            if (B.m != n)
            {
                throw new System.ArgumentException("Sparse natrix inner dimensions must agree.");
            }

            var C = new SparseDoubleMatrix(m, B.n);
            int idx, ii;

            for (int i = 0; i < m; i++)
            {
                if (indices[i] != null)
                {
                    for (int j = 0; j < B.n; j++)
                    {
                        for (int jj = 0; jj < count[i]; jj++)
                        {
                            ii = indices[i][jj];
                            if (B.indices[ii] != null)
                            {
                                idx = Array.BinarySearch(B.indices[ii], 0, B.count[ii], j);
                                if (idx >= 0)
                                {
                                    C[i, j] += items[i][jj] * B.items[ii][idx];
                                }
                            }
                        }
                    }
                }
            }

            return(C);
        }
        public void MapTest3()
        {
            int N = 6;

            var m1 = new SparseDoubleMatrix(N, N);
            var m2 = new SparseDoubleMatrix(N, N);

            // Pre-fill m2 elements right of the diagonal with values, these values should be discarded;
            for (int i = 0; i < N - 1; ++i)
            {
                m2[i, i + 1] = i * 13;
            }

            // Fill matrix m2 diagonal elements with 66
            m1.MapSparseIncludingDiagonal((a, r, c) => a + (r == c ? 66 : 0), m2);

            for (int i = 0; i < m2.RowCount; ++i)
            {
                for (int j = 0; j < m2.ColumnCount; ++j)
                {
                    Assert.AreEqual(i == j ? 66 : 0, m2[i, j]);
                }
            }

            // the same should work with the now already used matrix
            // fill diagonal now with 77
            m1.MapSparseIncludingDiagonal((a, r, c) => a + (r == c ? 77 : 0), m2);

            for (int i = 0; i < m2.RowCount; ++i)
            {
                for (int j = 0; j < m2.ColumnCount; ++j)
                {
                    Assert.AreEqual(i == j ? 77 : 0, m2[i, j]);
                }
            }
        }
        public void TimesEqualsTest()
        {
            const int N = 50;
            var       A = SparseDoubleMatrix.Identity(N, N);

            for (int i = 0; i < N; i++)
            {
                A[i, i] = i % 5 == 0 ? 1.0 : 0.0;
            }

            SparseDoubleMatrix AInit = A.Clone();
            SparseDoubleMatrix B     = A.Clone();

            for (int i = 0; i < N; i++)
            {
                B[i, i] = i % 5 == 0 ? 2.0 : 0.0;
            }
            var C = A.Mul(2.0);

            AssertMatrixEqualsEps(B, C);
            var D = AInit * 2.0;

            AssertMatrixEqualsEps(B, D);
        }
Exemple #15
0
        /// <summary>Solves system of linear equations Ax = b using Gaussian elimination with partial pivoting</summary>
        /// <param name="A">Sparse matrix, 'A'. This matrix is modified during solution!</param>
        /// <param name="b">Right part, 'b', is modified during solution.</param>
        /// <param name="x">Vector to store the solution.</param>
        public void SolveDestructive(SparseDoubleMatrix A, double[] b, double[] x)
        {
            if (A == null)
            {
                throw new ArgumentNullException(nameof(A));
            }
            if (b == null)
            {
                throw new ArgumentNullException(nameof(b));
            }
            if (x == null)
            {
                throw new ArgumentNullException(nameof(x));
            }
            int n = A.RowCount;

            if (!(n == b.Length))
            {
                throw new RankException("Mismatch between number of rows of the matrix A and length of vector b");
            }
            if (!(A.ColumnCount == x.Length))
            {
                throw new RankException("Mismatch between number of columns of the matrix A and length of vector x");
            }

            for (int j = 0; j < n; j++)
            {
                // Find row with largest absolute value of j-st element
                int    maxIdx = 0;
                double maxVal = A[maxIdx, j];
                double Aij    = 0.0;
                for (int i = 0; i < n - j; i++)
                {
                    Aij = A[i, j];
                    if (Math.Abs(Aij) > Math.Abs(maxVal))
                    {
                        maxIdx = i;
                        maxVal = Aij;
                    }
                }

                if (Math.Abs(maxVal) < 1e-12)
                {
                    throw new InvalidOperationException("Cannot apply Gauss method");
                }

                // Divide this row by max value
                A.ScaleRow(maxIdx, j + 1, n - 1, 1 / maxVal);
                b[maxIdx]   /= maxVal;
                A[maxIdx, j] = 1.0;

                // Move this row to bottom
                if (maxIdx != n - j - 1)
                {
                    A.SwitchRows(maxIdx, n - j - 1);

                    var temp3 = b[n - j - 1];
                    b[n - j - 1] = b[maxIdx];
                    b[maxIdx]    = temp3;
                }

                // Process all other rows
                for (int i = 0; i < n - j - 1; i++)
                {
                    Aij = A[i, j];
                    if (Aij != 0)
                    {
                        var indices = A.GetIndicesOfRow(n - j - 1);
                        foreach (int k in indices)
                        {
                            if (k > j)
                            {
                                A[i, k] -= Aij * A[n - j - 1, k];
                            }
                        }
                        b[i]   -= Aij * b[n - j - 1];
                        A[i, j] = 0;
                    }
                }
            }

            // Build answer
            for (int i = 0; i < n; i++)
            {
                double s  = b[i];
                var    Ai = A.GetRow(i);
                for (int k = 0; k < Ai.count; k++)
                {
                    if (Ai.indices[k] >= n - i)
                    {
                        s -= x[Ai.indices[k]] * A.GetRow(i).items[k];
                    }
                }
                x[n - i - 1] = s;
            }
        }