public void MatrixSolve4()
 {
     Matrix ma = new Matrix(new double[][] { new double[] { 1, 2, 3 }, new double[] { 5, 7, 11 }, new double[] { 13, 17, 19 } });
     Matrix mx = new Matrix(new double[][] { new double[] { 23 }, new double[] { 29 }, new double[] { 31 } });
     Matrix mb = ma * mx;
     Assert.That(ma.Solve(mb), NumericIs.AlmostEqualTo(mx));
 }
        public void SolveLinearSystem(
            [Values(10, 20, 50, 100, 200, 500)] int n)
        {
            double[][] a = Matrix.CreateMatrixData(n, n);
            double[][] x = Matrix.CreateMatrixData(n, 1);

            for(int i = 0; i < n; i++)
            {
                for(int j = 0; j < n; j++)
                {
                    if(j == 0)
                    {
                        x[i][0] = Rnd.NextDouble();
                    }

                    a[i][j] = Rnd.NextDouble();
                }
            }

            Matrix ma = new Matrix(a);
            Matrix mx = new Matrix(x);
            Matrix mb = ma*mx;
            Assert.That(ma.Solve(mb), NumericIs.AlmostEqualTo(mx, 1e-10));
        }
 public void MatrixSolve3()
 {
     Matrix ma = new Matrix(new double[][] { new double[] { 1, 2 }, new double[] { 3, 5 } });
     Matrix mx = new Matrix(new double[][] { new double[] { 7 }, new double[] { 11.0 } });
     Matrix mb = ma * mx;
     Assert.That(ma.Solve(mb), NumericIs.AlmostEqualTo(mx));
 }
 public void MatrixSolve2()
 {
     Matrix ma = new Matrix(new double[][] { new double[] { 1, 2 }, new double[] { 3, 5 } });
     Matrix mb = new Matrix(new double[][] { new double[] { 29.0 }, new double[] { 76.0 } });
     Matrix mr = new Matrix(new double[][] { new double[] { 7 }, new double[] { 11.0 } });
     Matrix mx = ma.Solve(mb);
     Assert.That(mx, NumericIs.AlmostEqualTo(mr));
     Assert.That(ma * mx, NumericIs.AlmostEqualTo(mb));
 }
        public void AllTests()
        {
            Matrix A, B, C, Z, O, I, R, S, X, SUB, M, T, SQ, DEF, SOL;
            double tmp;
            double[] columnwise = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 };
            double[] rowwise = { 1.0, 4.0, 7.0, 10.0, 2.0, 5.0, 8.0, 11.0, 3.0, 6.0, 9.0, 12.0 };
            double[][] avals = { new double[] { 1.0, 4.0, 7.0, 10.0 }, new double[] { 2.0, 5.0, 8.0, 11.0 }, new double[] { 3.0, 6.0, 9.0, 12.0 } };
            double[][] rankdef = avals;
            double[][] tvals = { new double[] { 1.0, 2.0, 3.0 }, new double[] { 4.0, 5.0, 6.0 }, new double[] { 7.0, 8.0, 9.0 }, new double[] { 10.0, 11.0, 12.0 } };
            double[][] subavals = { new double[] { 5.0, 8.0, 11.0 }, new double[] { 6.0, 9.0, 12.0 } };
            double[][] pvals = { new double[] { 25, -5, 10 }, new double[] { -5, 17, 10 }, new double[] { 10, 10, 62 } };
            double[][] ivals = { new double[] { 1.0, 0.0, 0.0, 0.0 }, new double[] { 0.0, 1.0, 0.0, 0.0 }, new double[] { 0.0, 0.0, 1.0, 0.0 } };
            double[][] evals = { new double[] { 0.0, 1.0, 0.0, 0.0 }, new double[] { 1.0, 0.0, 2e-7, 0.0 }, new double[] { 0.0, -2e-7, 0.0, 1.0 }, new double[] { 0.0, 0.0, 1.0, 0.0 } };
            double[][] square = { new double[] { 166.0, 188.0, 210.0 }, new double[] { 188.0, 214.0, 240.0 }, new double[] { 210.0, 240.0, 270.0 } };
            double[][] sqSolution = { new double[] { 13.0 }, new double[] { 15.0 } };
            double[][] condmat = { new double[] { 1.0, 3.0 }, new double[] { 7.0, 9.0 } };
            int rows = 3, cols = 4;
            int invalidld = 5; /* should trigger bad shape for construction with val */
            int validld = 3; /* leading dimension of intended test Matrices */
            int nonconformld = 4; /* leading dimension which is valid, but nonconforming */
            int ib = 1, ie = 2, jb = 1, je = 3; /* index ranges for sub Matrix */
            int[] rowindexset = new int[] { 1, 2 };
            int[] badrowindexset = new int[] { 1, 3 };
            int[] columnindexset = new int[] { 1, 2, 3 };
            int[] badcolumnindexset = new int[] { 1, 2, 4 };
            double columnsummax = 33.0;
            double rowsummax = 30.0;
            double sumofdiagonals = 15;
            double sumofsquares = 650;

            #region Testing constructors and constructor-like methods

            // Constructors and constructor-like methods:
            // double[], int
            // double[,]  
            // int, int
            // int, int, double
            // int, int, double[,]
            // Create(double[,])
            // Random(int,int)
            // Identity(int)

            try
            {
                // check that exception is thrown in packed constructor with invalid length
                A = new Matrix(columnwise, invalidld);
                Assert.Fail("Catch invalid length in packed constructor: exception not thrown for invalid input");
            }
            catch(ArgumentException) { }

            A = new Matrix(columnwise, validld);
            B = new Matrix(avals);
            tmp = B[0, 0];
            avals[0][0] = 0.0;
            C = B - A;
            avals[0][0] = tmp;
            B = Matrix.Create(avals);
            tmp = B[0, 0];
            avals[0][0] = 0.0;
            Assert.AreEqual((tmp - B[0, 0]), 0.0, "Create");

            avals[0][0] = columnwise[0];
            I = new Matrix(ivals);
            NumericAssert.AreAlmostEqual(I, Matrix.Identity(3, 4), "Identity");

            #endregion

            #region Testing access methods

            // Access Methods:
            // getColumnDimension()
            // getRowDimension()
            // getArray()
            // getArrayCopy()
            // getColumnPackedCopy()
            // getRowPackedCopy()
            // get(int,int)
            // GetMatrix(int,int,int,int)
            // GetMatrix(int,int,int[])
            // GetMatrix(int[],int,int)
            // GetMatrix(int[],int[])
            // set(int,int,double)
            // SetMatrix(int,int,int,int,Matrix)
            // SetMatrix(int,int,int[],Matrix)
            // SetMatrix(int[],int,int,Matrix)
            // SetMatrix(int[],int[],Matrix)

            // Various get methods
            B = new Matrix(avals);
            Assert.AreEqual(B.RowCount, rows, "getRowDimension");
            Assert.AreEqual(B.ColumnCount, cols, "getColumnDimension");

            B = new Matrix(avals);
            double[][] barray = (Matrix)B;
            Assert.AreSame(barray, avals, "getArray");

            barray = B.Clone();
            Assert.AreNotSame(barray, avals, "getArrayCopy");
            NumericAssert.AreAlmostEqual(new Matrix(barray), B, "getArrayCopy II");

            //            double[] bpacked = B.ColumnPackedCopy;
            //            try
            //            {
            //                check(bpacked, columnwise);
            //                try_success("getColumnPackedCopy... ", "");
            //            }
            //            catch (System.SystemException e)
            //            {
            //                errorCount = try_failure(errorCount, "getColumnPackedCopy... ", "data not successfully (deep) copied by columns");
            //                System.Console.Out.WriteLine(e.Message);
            //            }
            //            bpacked = B.RowPackedCopy;
            //            try
            //            {
            //                check(bpacked, rowwise);
            //                try_success("getRowPackedCopy... ", "");
            //            }
            //            catch (System.SystemException e)
            //            {
            //                errorCount = try_failure(errorCount, "getRowPackedCopy... ", "data not successfully (deep) copied by rows");
            //                System.Console.Out.WriteLine(e.Message);
            //            }

            try
            {
                tmp = B[B.RowCount, B.ColumnCount - 1];
                Assert.Fail("get(int,int): OutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                tmp = B[B.RowCount - 1, B.ColumnCount];
                Assert.Fail("get(int,int): OutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }
            Assert.AreEqual(B[B.RowCount - 1, B.ColumnCount - 1], avals[B.RowCount - 1][B.ColumnCount - 1], "get(int,int)");

            SUB = new Matrix(subavals);
            try
            {
                M = B.GetMatrix(ib, ie + B.RowCount + 1, jb, je);
                Assert.Fail("GetMatrix(int,int,int,int): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(ib, ie, jb, je + B.ColumnCount + 1);
                Assert.Fail("GetMatrix(int,int,int,int): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            M = B.GetMatrix(ib, ie, jb, je);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int,int,int,int)");

            try
            {
                M = B.GetMatrix(ib, ie, badcolumnindexset);
                Assert.Fail("GetMatrix(int,int,int[]): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(ib, ie + B.RowCount + 1, columnindexset);
                Assert.Fail("GetMatrix(int,int,int[]): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            M = B.GetMatrix(ib, ie, columnindexset);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int,int,int[])");

            try
            {
                M = B.GetMatrix(badrowindexset, jb, je);
                Assert.Fail("GetMatrix(int[],int,int): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(rowindexset, jb, je + B.ColumnCount + 1);
                Assert.Fail("GetMatrix(int[],int,int): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            M = B.GetMatrix(rowindexset, jb, je);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int[],int,int)");

            try
            {
                M = B.GetMatrix(badrowindexset, columnindexset);
                Assert.Fail("GetMatrix(int[],int[]): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                M = B.GetMatrix(rowindexset, badcolumnindexset);
                Assert.Fail("GetMatrix(int[],int[]): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            M = B.GetMatrix(rowindexset, columnindexset);
            NumericAssert.AreAlmostEqual(SUB, M, "GetMatrix(int[],int[])");

            // Various set methods:
            try
            {
                B[B.RowCount, B.ColumnCount - 1] = 0.0;
                Assert.Fail("set(int,int,double): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                B[B.RowCount - 1, B.ColumnCount] = 0.0;
                Assert.Fail("set(int,int,double): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            B[ib, jb] = 0.0;
            tmp = B[ib, jb];
            NumericAssert.AreAlmostEqual(tmp, 0.0, "set(int,int,double)");

            M = new Matrix(2, 3, 0.0);
            try
            {
                B.SetMatrix(ib, ie + B.RowCount + 1, jb, je, M);
                Assert.Fail("SetMatrix(int,int,int,int,Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(ib, ie, jb, je + B.ColumnCount + 1, M);
                Assert.Fail("SetMatrix(int,int,int,int,Matrix): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            B.SetMatrix(ib, ie, jb, je, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(ib, ie, jb, je), M, "SetMatrix(int,int,int,int,Matrix)");
            B.SetMatrix(ib, ie, jb, je, SUB);
            try
            {
                B.SetMatrix(ib, ie + B.RowCount + 1, columnindexset, M);
                Assert.Fail("SetMatrix(int,int,int[],Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(ib, ie, badcolumnindexset, M);
                Assert.Fail("SetMatrix(int,int,int[],Matrix): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            B.SetMatrix(ib, ie, columnindexset, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(ib, ie, columnindexset), M, "SetMatrix(int,int,int[],Matrix)");
            B.SetMatrix(ib, ie, jb, je, SUB);
            try
            {
                B.SetMatrix(rowindexset, jb, je + B.ColumnCount + 1, M);
                Assert.Fail("SetMatrix(int[],int,int,Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(badrowindexset, jb, je, M);
                Assert.Fail("SetMatrix(int[],int,int,Matrix): IndexOutOfBoundsException expected but not thrown II");
            }
            catch(IndexOutOfRangeException) { }

            B.SetMatrix(rowindexset, jb, je, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(rowindexset, jb, je), M, "SetMatrix(int[],int,int,Matrix)");

            B.SetMatrix(ib, ie, jb, je, SUB);
            try
            {
                B.SetMatrix(rowindexset, badcolumnindexset, M);
                Assert.Fail("SetMatrix(int[],int[],Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }
            try
            {
                B.SetMatrix(badrowindexset, columnindexset, M);
                Assert.Fail("SetMatrix(int[],int[],Matrix): IndexOutOfBoundsException expected but not thrown");
            }
            catch(IndexOutOfRangeException) { }

            B.SetMatrix(rowindexset, columnindexset, M);
            NumericAssert.AreAlmostEqual(M - B.GetMatrix(rowindexset, columnindexset), M, "SetMatrix(int[],int[],Matrix)");

            #endregion

            #region Testing array-like methods

            // Array-like methods:
            // Subtract
            // SubtractEquals
            // Add
            // AddEquals
            // ArrayLeftDivide
            // ArrayLeftDivideEquals
            // ArrayRightDivide
            // ArrayRightDivideEquals
            // arrayTimes
            // ArrayMultiplyEquals
            // uminus

            S = new Matrix(columnwise, nonconformld);
            R = Matrix.Random(A.RowCount, A.ColumnCount);
            A = R;
            try
            {
                S = A - S;
                Assert.Fail("Subtract conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }
            Assert.AreEqual((A - R).Norm1(), 0.0, "Subtract: difference of identical Matrices is nonzero,\nSubsequent use of Subtract should be suspect");

            A = R.Clone();
            A.Subtract(R);
            Z = new Matrix(A.RowCount, A.ColumnCount);
            try
            {
                A.Subtract(S);
                Assert.Fail("SubtractEquals conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }
            Assert.AreEqual((A - Z).Norm1(), 0.0, "SubtractEquals: difference of identical Matrices is nonzero,\nSubsequent use of Subtract should be suspect");

            A = R.Clone();
            B = Matrix.Random(A.RowCount, A.ColumnCount);
            C = A - B;
            try
            {
                S = A + S;
                Assert.Fail("Add conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }
            NumericAssert.AreAlmostEqual(C + B, A, "Add");

            C = A - B;
            C.Add(B);
            try
            {
                A.Add(S);
                Assert.Fail("AddEquals conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }
            NumericAssert.AreAlmostEqual(C, A, "AddEquals");

            A = ((Matrix)R.Clone());
            A.UnaryMinus();
            NumericAssert.AreAlmostEqual(A + R, Z, "UnaryMinus");

            A = (Matrix)R.Clone();
            O = new Matrix(A.RowCount, A.ColumnCount, 1.0);
            try
            {
                Matrix.ArrayDivide(A, S);
                Assert.Fail("ArrayRightDivide conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }

            C = Matrix.ArrayDivide(A, R);
            NumericAssert.AreAlmostEqual(C, O, "ArrayRightDivide");
            try
            {
                A.ArrayDivide(S);
                Assert.Fail("ArrayRightDivideEquals conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }

            A.ArrayDivide(R);
            NumericAssert.AreAlmostEqual(A, O, "ArrayRightDivideEquals");

            A = (Matrix)R.Clone();
            B = Matrix.Random(A.RowCount, A.ColumnCount);
            try
            {
                S = Matrix.ArrayMultiply(A, S);
                Assert.Fail("arrayTimes conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }

            C = Matrix.ArrayMultiply(A, B);
            C.ArrayDivide(B);
            NumericAssert.AreAlmostEqual(C, A, "arrayTimes");
            try
            {
                A.ArrayMultiply(S);
                Assert.Fail("ArrayMultiplyEquals conformance check: nonconformance not raised");
            }
            catch(ArgumentException) { }

            A.ArrayMultiply(B);
            A.ArrayDivide(B);
            NumericAssert.AreAlmostEqual(A, R, "ArrayMultiplyEquals");

            #endregion

            #region Testing linear algebra methods

            // LA methods:
            // Transpose
            // Multiply
            // Condition
            // Rank
            // Determinant
            // trace
            // Norm1
            // norm2
            // normF
            // normInf
            // Solve
            // solveTranspose
            // Inverse
            // chol
            // Eigen
            // lu
            // qr
            // svd 

            A = new Matrix(columnwise, 3);
            T = new Matrix(tvals);
            T = Matrix.Transpose(A);
            NumericAssert.AreAlmostEqual(Matrix.Transpose(A), T, "Transpose");
            NumericAssert.AreAlmostEqual(A.Norm1(), columnsummax, "Norm1");
            NumericAssert.AreAlmostEqual(A.NormInf(), rowsummax, "NormInf");
            NumericAssert.AreAlmostEqual(A.NormF(), Math.Sqrt(sumofsquares), "NormF");
            NumericAssert.AreAlmostEqual(A.Trace(), sumofdiagonals, "Trace");
            NumericAssert.AreAlmostEqual(A.GetMatrix(0, A.RowCount - 1, 0, A.RowCount - 1).Determinant(), 0.0, "Determinant");

            SQ = new Matrix(square);
            NumericAssert.AreAlmostEqual(A * Matrix.Transpose(A), SQ, "Multiply(Matrix)");
            NumericAssert.AreAlmostEqual(0.0 * A, Z, "Multiply(double)");

            A = new Matrix(columnwise, 4);
            QRDecomposition QR = A.QRDecomposition;
            R = QR.R;
            NumericAssert.AreAlmostEqual(A, QR.Q * R, "QRDecomposition");

            SingularValueDecomposition SVD = A.SingularValueDecomposition;
            NumericAssert.AreAlmostEqual(A, SVD.LeftSingularVectors * (SVD.S * Matrix.Transpose(SVD.RightSingularVectors)), "SingularValueDecomposition");

            DEF = new Matrix(rankdef);
            NumericAssert.AreAlmostEqual(DEF.Rank(), Math.Min(DEF.RowCount, DEF.ColumnCount) - 1, "Rank");

            B = new Matrix(condmat);
            SVD = B.SingularValueDecomposition;
            double[] singularvalues = SVD.SingularValues;
            NumericAssert.AreAlmostEqual(B.Condition(), singularvalues[0] / singularvalues[Math.Min(B.RowCount, B.ColumnCount) - 1], "Condition");

            int n = A.ColumnCount;
            A = A.GetMatrix(0, n - 1, 0, n - 1);
            A[0, 0] = 0.0;
            LUDecomposition LU = A.LUDecomposition;
            NumericAssert.AreAlmostEqual(A.GetMatrix(LU.Pivot, 0, n - 1), LU.L * LU.U, "LUDecomposition");

            X = A.Inverse();
            NumericAssert.AreAlmostEqual(A * X, Matrix.Identity(3, 3), "Inverse");

            O = new Matrix(SUB.RowCount, 1, 1.0);
            SOL = new Matrix(sqSolution);
            SQ = SUB.GetMatrix(0, SUB.RowCount - 1, 0, SUB.RowCount - 1);
            NumericAssert.AreAlmostEqual(SQ.Solve(SOL), O, "Solve");

            A = new Matrix(pvals);
            CholeskyDecomposition Chol = A.CholeskyDecomposition;
            Matrix L = Chol.TriangularFactor;
            NumericAssert.AreAlmostEqual(A, L * Matrix.Transpose(L), "CholeskyDecomposition");

            X = Chol.Solve(Matrix.Identity(3, 3));
            NumericAssert.AreAlmostEqual(A * X, Matrix.Identity(3, 3), "CholeskyDecomposition Solve");

            EigenvalueDecomposition Eig = A.EigenvalueDecomposition;
            Matrix D = Eig.BlockDiagonal;
            Matrix V = Eig.EigenVectors;
            NumericAssert.AreAlmostEqual(A * V, V * D, "EigenvalueDecomposition (symmetric)");

            A = new Matrix(evals);
            Eig = A.EigenvalueDecomposition;
            D = Eig.BlockDiagonal;
            V = Eig.EigenVectors;
            NumericAssert.AreAlmostEqual(A * V, V * D, "EigenvalueDecomposition (nonsymmetric)");

            #endregion
        }
예제 #6
0
        public void CodeSample_PolynomialRegression()
        {
            double[] x = new double[] { 1000, 2000, 3000, 4000, 5000, 6000, 7000 };
            double[] y = new double[] { -30, -60, -88, -123, -197, -209, -266 };
            int polynomialOrder = 3;

            // Build the matrix for the least-squares fitting
            double[][] m = Matrix.CreateMatrixData(x.Length, polynomialOrder + 1);
            for(int i = 0; i < x.Length; i++)
            {
                double xi = x[i];
                double[] xrow = m[i];
                xrow[0] = 1d;
                for(int j = 1; j < xrow.Length; j++)
                {
                    xrow[j] = xrow[j - 1] * xi;
                }
            }

            // Find the least-squares solution
            Matrix matrix = new Matrix(m);
            Vector solution = matrix.Solve(y);

            // Extract the values (in our case into a polynomial for fast evaluation)
            Polynomial polynomial = new Polynomial(solution);

            // Verify that the polynomial fits with less than 10% error for all given value pairs.
            for(int i = 0; i < x.Length; i++)
            {
                Assert.That(polynomial.Evaluate(x[i]), NumericIs.AlmostEqualTo(y[i], 0.1), i.ToString());
            }
        }
        /*Test a given solution by calculating b and then solving for x.
        Shows only the elapsed time on console out so that we can use 
        matrices too large to print.*/
        private Matrix TestMatrix_Solutions(Matrix ma, Matrix mx, double epsilon, bool showB)
        {
            Matrix mb = ma * mx;
            if(showB)
            {
                Console.WriteLine("b");
                Console.WriteLine(mb.ToString());
            }
            Matrix ms = null;
            MyStopwatch.MethodToTime m = delegate
            {
                ms = ma.Solve(mb);
            };
            Console.Write("Solve Time (ms) for " + ma.ColumnCount + ": ");
            MyStopwatch.Time(m);

            Assert.IsTrue(CompareMatrices(ms, mx, epsilon), "Matrices should be equal");
            //Assert.AreEqual(ms.ToString(), mx.ToString(), "Matrices should be equal");

            return ms;
        }
예제 #8
0
        // Performs a Kalman update on track using measurement and overwrites track with new estimate
        public GaussianTrack Estimate(List<GaussianMeasurement> measurements)
        {
            // Understand input
            int N = measurements.Count;

            // Check if we have sufficient samples to estimate
            if (N < minBatchMeasurements)
            {
                return null;
            }
            
            // Sort the list by datetime
            measurements.Sort((x,y) => x.dateTime.CompareTo(y.dateTime));

            // Prealloc structures
            Matrix A = new Matrix(3 * N, 6, 0);
            Matrix g = new Matrix(3 * N, 1, 0);
            Matrix R = new Matrix(3 * N, 3 * N, 0);

            // Go through each measurements
            for (int k = 0; k < N; k++)
            {
                // Compute time difference
                double dt = measurements[k].dateTime.Subtract(measurements[N - 1].dateTime).TotalSeconds;
                
                // Populate (3x6) block of A
                A[3 * k, 0] = 1;
                A[3 * k + 1, 1] = 1;
                A[3 * k + 2, 2] = 1;
                A[3 * k, 3] = dt;
                A[3 * k + 1, 4] = dt;
                A[3 * k + 2, 5] = dt;

                // Convert measurement to Unity (track) space
                Vector convMean;
                Matrix convJacobian;
                Coordinate.Convert(measurements[k].creatorUnityReference, measurements[k].coordinateType,
                    measurements[k].gaussianVector.mean, new Vector(3), Coordinate.Type.UNITY3,
                    out convMean, out convJacobian);
                Matrix convJacobianT = convJacobian.Clone();
                convJacobianT.Transpose();
                Matrix convCovariance = convJacobian * measurements[k].gaussianVector.covariance * convJacobianT;

                // Populate (3x1) block of g with converted measurement mean
                g[3 * k, 0] = convMean[0]; 
                g[3 * k + 1, 0] = convMean[1];
                g[3 * k + 2, 0] = convMean[2];

                // Copy coverted measurement covariance to (3x3) block in R matrix
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        R[3*k + i, 3*k + j] = convCovariance[i, j];
                    }
                }
            }

            // Finished building A, g, R matrices
            // Compute weighted least squares fit
            // Ps = inv(A'*inv(R)*A)
            // Xs = Ps*A'*inv(R)*g
            Matrix AT = A.Clone();
            AT.Transpose();
            Matrix Ps = (AT * R.Solve(A)).Inverse();
            Vector Xs = (Ps * AT * R.Solve(g)).GetColumnVector(0);

            // Create a new track and return
            return new GaussianTrack(fusionEngine.RequestNewTrackID(), 
                new GaussianVector(Xs, Ps), Coordinate.Type.UNITY6, 
                measurements[N - 1].dateTime);
        }
예제 #9
0
        /*
         * Gute Parameterwerte sind (mit angepasster GUI):
         *
         * a = 0.05
         * Search Range = 50
         * k = 5
         * Ransac Steps = 10000
         * Ransac Threshold = 0.1
         *
         */
        /// <summary>
        /// Berechnet eine Homographie aus korrespondierenden Punktepaaren. Benutzt die Methode aus 
        /// "Computer Vision: Algorithms and Applications" von Richard Szeliski, http://szeliski.org/Book/. Kapitel 6.1,
        /// insbesondere 6.1.3
        /// </summary>
        /// <param name="sourcePoints">Punkte im linken Bild</param>
        /// <param name="targetPoints">Punkte im rechten Bild</param>
        /// <returns>Homographiematrix</returns>
        private double[,] getHomographyFromPoints(double[,] affineMatrix, PointF[] sourcePoints, PointF[] targetPoints)
        {
            //Bezeichnungen orientieren sich an den Bezeichnungein in 6.1.3
            Matrix deltaP, A, b, ri;
            ri = new Matrix(2, 1);
            double lambda = 0;

            //Jacobi Matrix und Transponierte
            Matrix J, Jt;
            //Anzahl der Matches
            int nPoints = sourcePoints.Length;
            //von der Homographie vorausgesagte Position von p (siehe (6.3))
            PointF predLoc;
            //Berechne Initial guess von deltaP: In unserem Fall sind die Bilder fast affin verschoben.
            //Also ist die affine Schätzung ein guter Anfang
            deltaP = new Matrix(8, 1);
            //double[,] affineMatrix = getHomographyFromPointsOld(sourcePoints, targetPoints);
            deltaP[0, 0] = affineMatrix[0, 0] - 1; //wegen Konvention in 6.1.3, zweiter Absatz
            deltaP[1, 0] = affineMatrix[0, 1];
            deltaP[2, 0] = affineMatrix[0, 2];
            deltaP[3, 0] = affineMatrix[1, 0];
            deltaP[4, 0] = affineMatrix[1, 1] - 1;
            deltaP[5, 0] = affineMatrix[1, 2];
            deltaP[6, 0] = affineMatrix[2, 0];
            deltaP[7, 0] = affineMatrix[2, 1];

            //Algorithmus iterieren
            int iterations = 100;
            A = new Matrix(8, 8);
            b = new Matrix(8, 1);
            for (int step = 0; step < iterations; step++)
            {
                //compute A und B:
                for (int i = 0; i < nPoints; i++)
                {
                    //Jacobimatrix berechnen
                    J = getJacobi(deltaP, sourcePoints[i]);
                    Jt = J.Clone();
                    //Transponierte Jacobimatrix berechnen
                    Jt.Transpose();

                    //sourcePoints[i] mit aktueller Homographie abbilden
                    double[,] thisH = new double[3, 3];
                    thisH[0, 0] = deltaP[0, 0] + 1;
                    thisH[0, 1] = deltaP[1, 0];
                    thisH[0, 2] = deltaP[2, 0];
                    thisH[1, 0] = deltaP[3, 0];
                    thisH[1, 1] = deltaP[4, 0] + 1;
                    thisH[1, 2] = deltaP[5, 0];
                    thisH[2, 0] = deltaP[6, 0];
                    thisH[2, 1] = deltaP[7, 0];
                    thisH[2, 2] = 1;
                    predLoc = projectPoint(thisH, sourcePoints[i]);

                    //ri berechnen (6.10)
                    ri[0, 0] = targetPoints[i].X - predLoc.X;
                    ri[1, 0] = targetPoints[i].Y - predLoc.Y;
                    //A und b updaten (6.9) und (6.10)
                    A.Add(Jt.Multiply(J));
                    b.Add(Jt.Multiply(ri));
                }
                //numerischer Trick (6.18)
                for (int j = 0; j < 8; j++)
                    A[j, j] += A[j, j] * lambda;
                //lasse Schritte, in denen A singulär ist, aus, passiert aber sowieso fast nie
                try
                {
                    //nach deltaP lösen und deltaP auf das aktuelle p (=deltaP) addieren (6.18)
                    deltaP.Add(A.Solve(b));
                }
                catch
                {   }
            }

            //lese deltaP aus
            double[,] homography = new double[3, 3];
            homography[0, 0] = deltaP[0, 0] + 1;
            homography[0, 1] = deltaP[1, 0];
            homography[0, 2] = deltaP[2, 0];
            homography[1, 0] = deltaP[3, 0];
            homography[1, 1] = deltaP[4, 0] + 1;
            homography[1, 2] = deltaP[5, 0];
            homography[2, 0] = deltaP[6, 0];
            homography[2, 1] = deltaP[7, 0];
            homography[2, 2] = 1;
            return homography;
        }
예제 #10
0
        /// <summary>
        /// Findet in den korrespondierenden Punktepaaren correspondences eine affine Homographie mittels RANSAC
        /// </summary>
        /// <param name="imageL">Das linke Bild</param>
        /// <param name="imageR">Das rechte Bild</param>
        /// <param name="correspondences">Menge von korrespondierenden Punktepaaren, wobei erwartet wird, dass kein Punktepaar doppelt vorkommt</param>
        /// <returns>affine Homographiematrix, die die Transformation zwischen linkem und rechtem Bild beschreibt</returns>
        public override double[,] ransacH(
            Image<Bgr, byte> imageL,
            Image<Bgr, byte> imageR, 
            Match[] correspondences, 
            int ransacSteps, 
            double ransacThresh)
        {
            Random rng = new Random();
            Matrix L, R, H;

            // Anzahl der Korrespondenzen
            int n = correspondences.Length;

            //Sicherstellen, dass mindestens 3 Korrespondenzen vorhand sind, damit das GLS (sieh unten) eindeutig gelöst werden kann
            if (n < 3) throw new Exception("Nicht genug Korrespondenzen gefunden!");

            // Speicherplätze für ConsensusSets:
            // das aktuell verarbeitete; das mit bisher am meisten Elementen
            List<Match> currConsensusSet, biggestConsensusSet = new List<Match>();

            for (int i = 0; i < ransacSteps; i++)
            {
                // Die Matrizen für das zu lösende GLS mit drei zufälligen, verschiedenen Punkten erstellen:
                List<Match> matches = new List<Match>(); //Speicherplatz für drei zufällig ausgewählte, verschiedene Korrespondenzen
                L = new Matrix(3, 3); // enthält drei Punkte aus dem linken Bild (vgl. linke Matrix des GLS vom Aufgabenblatt)
                R = new Matrix(3, 3); // enthält drei punkte aus dem rechten Bild (vgl. rechte Matrix des GLS vom Aufgabenblatt)
                for (int j = 0; j < 3; j++)
                {
                    int index;
                    do
                        index = rng.Next(n); //zufällige, neue Korrespondenz holen
                    while (matches.Contains(correspondences[index]));
                    matches.Add(correspondences[index]);
                    //Die beiden Punkte der aktuellen Korrespondenz den Matrizen hinzufügen
                    L[j, 0] = correspondences[index].p1.X;
                    L[j, 1] = correspondences[index].p1.Y;
                    L[j, 2] = 1;
                    R[j, 0] = correspondences[index].p2.X;
                    R[j, 1] = correspondences[index].p2.Y;
                    R[j, 2] = 1;
                }

                //lasse Schritte, in denen A singulär ist, aus, passiert aber sowieso fast nie
                try
                {
                    H = R.Solve(L); //Das GLS (vgl. Aufgabenblatt) lösen lassen, um die transponierte Homographie-Matrix zu erhalten
                    H.Transpose(); // Die transponierte Homographie-Matrix transponieren, um die Homographie-Matrix zu erhalten
                }
                catch { continue; }

                // Bestimmen des ConsensusSets:
                currConsensusSet = new List<Match>();
                for (int j = 0; j < n; j++)
                {
                    // Rechter Punkt der aktuellen Korrespondenz mit der Homographie-Matrix transformieren
                    // und den (euklidschen) Abstand zum linken Punkt berechnen
                    PointF rightPointTransformed = new PointF();
                    rightPointTransformed.X = (float)(H[0, 0] * correspondences[j].p2.X + H[0, 1] * correspondences[j].p2.Y + H[0, 2]);
                    rightPointTransformed.Y = (float)(H[1, 0] * correspondences[j].p2.X + H[1, 1] * correspondences[j].p2.Y + H[1, 2]);
                    float z = (float)(H[2, 0] + H[2, 1] + H[2, 2]);
                    rightPointTransformed.X /= z;
                    rightPointTransformed.Y /= z;

                    //Abstand berechnen
                    double distance = Math.Sqrt((correspondences[j].p1.X - rightPointTransformed.X) * (correspondences[j].p1.X - rightPointTransformed.X) + (correspondences[j].p1.Y - rightPointTransformed.Y) * (correspondences[j].p1.Y - rightPointTransformed.Y));

                    // Wenn der Abstand des linken Punktes zum transformierten rechten Punkt noch im Rahmen liegt, hinzufügen:
                    if (distance < ransacThresh)
                        currConsensusSet.Add(correspondences[j]);
                }

                // Es wird das ConsensusSet gesucht, das die meisten Elemente enthält:
                if (currConsensusSet.Count > biggestConsensusSet.Count)
                    biggestConsensusSet = currConsensusSet;
            }

            //Nachdem des größte ConsensusSet gefunden wurde, muss dessen Homographie-Matrix mit Hilfe aller unterstützenden Punkte berechnet werden (analog zu oben)
            //Bei einer Überbestimmung des GLS wendet Solve als Ausgleichsverfahren leastSquares an
            L = new Matrix(biggestConsensusSet.Count, 3);
            R = new Matrix(biggestConsensusSet.Count, 3);
            for (int i = 0; i < biggestConsensusSet.Count; i++)
            {
                L[i, 0] = biggestConsensusSet[i].p1.X;
                L[i, 1] = biggestConsensusSet[i].p1.Y;
                L[i, 2] = 1;
                R[i, 0] = biggestConsensusSet[i].p2.X;
                R[i, 1] = biggestConsensusSet[i].p2.Y;
                R[i, 2] = 1;
            }
            H = R.Solve(L);
            H.Transpose();

            //correspondences in das passende Format für getHomographyFromPoints überführen
            var l = new PointF[correspondences.Length];
            var r = new PointF[correspondences.Length];
            for(int i = 0; i < correspondences.Length; i++)
            {
                l[i] = correspondences[i].p2;
                r[i] = correspondences[i].p1;
            }

            //Die gefundene affine Homographie-Matrix nutzen, um eine nicht-affine Matrix zu generieren
            //Ergebnis zurückgeben
            return getHomographyFromPoints(H.CopyToArray(), l, r);
        }