/// <summary>
        /// This method saves some time if both the inverse and the determinant is needed by only having to compute
        /// the inverse once.
        /// </summary>
        public static void InverseDeterminant(DualMatrix matrix, out DualMatrix inverse, out DualNumber determinant)
        {
            int m = matrix.Rows;

            if (matrix.Columns != m)
            {
                throw new ArgumentException("The matrix isn't a square matrix.");
            }

            if (m <= 3)
            {
                // The naive implementation seems to be faster (for all values of n). Maybe it's
                // faster to perform the LU decomposition directly on the DualNumbers?
                determinant = DeterminantDirect(m, matrix);
                inverse = InverseDirect(m, matrix, determinant);
                return;
            }

            int n = GradientLength(m, matrix);

            LUDecomposition lu = LUDecomposition.Decompose(matrix.GetValues());
            Matrix inverse0 = lu.Inverse();
            double determinant0 = lu.Determinant();

            inverse = Inverse(matrix, m, n, inverse0);
            determinant = Determinant(matrix, m, n, inverse0, determinant0);
        }
        public static void InverseDeterminant(DualMatrix matrix, out DualMatrix inverse, out DualNumber determinant)
        {
            int n = matrix.Rows;
            if (matrix.Columns != n)
            {
                throw new ArgumentException("The matrix is not a square matrix.");
            }

            DualNumber[,] a = matrix.ToArray();

            if (!spdmatrixcholesky(ref a, n, false))
            {
                throw new ArithmeticException();
            }

            determinant = spdmatrixcholeskydet(ref a, n);

            int info = 0;
            spdmatrixcholeskyinverse(ref a, n, false, ref info);

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    a[i, j] = a[j, i];
                }
            }

            inverse = new DualMatrix(a);
        }
        public static DualMatrix Inverse(DualMatrix matrix)
        {
            int n = matrix.Rows;
            if (matrix.Columns != n)
            {
                throw new ArgumentException("The matrix is not a square matrix.");
            }

            DualNumber[,] a = matrix.ToArray();
            int info = 0;
            spdmatrixinverse(ref a, n, false, ref info);
            if (info != 1)
            {
                throw new ArithmeticException();
            }

            for (int i = 0; i < n; i++)
            {
                for (int j = i + 1; j < n; j++)
                {
                    a[i, j] = a[j, i];
                }
            }

            return new DualMatrix(a);
        }
예제 #4
0
        public DualVector(DualNumber[] entries)
        {
            int n = entries.Length;

            DualNumber[,] a = new DualNumber[n, 1];
            for (int i = 0; i < n; i++)
            {
                a[i, 0] = entries[i];
            }

            inner = new DualMatrix(a);
        }
        public static DualMatrix Inverse(DualMatrix matrix)
        {
            int m = matrix.Rows;

            if (matrix.Columns != m)
            {
                throw new ArgumentException("The matrix isn't a square matrix.");
            }

            if (m <= 3)
            {
                DualNumber determinant = DeterminantDirect(m, matrix);
                return InverseDirect(m, matrix, determinant);
            }

            int n = GradientLength(m, matrix);

            return Inverse(matrix, m, n, LUDecomposition.Inverse(matrix.GetValues()));
        }
예제 #6
0
        public static DualMatrix Transpose(DualMatrix matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException();
            }

            int n = matrix.Columns;
            int m = matrix.Rows;

            DualMatrix b = new DualMatrix(n, m);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    b[i, j] = matrix[j, i];
                }
            }

            return b;
        }
예제 #7
0
        public static DualNumber Trace(DualMatrix matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException();
            }

            int n = matrix.Rows;

            if (matrix.Columns != n)
            {
                throw new ArgumentException("Non-square matrix.");
            }

            DualNumber s = 0.0;
            for (int i = 0; i < n; i++)
            {
                s += matrix[i, i];
            }

            return s;
        }
예제 #8
0
 public static DualMatrix Inverse(DualMatrix matrix)
 {
     // Use direct computation for low dimenstions; LU decomposition otherwise.
     return DualLUDecomposition.Inverse(matrix);
 }
예제 #9
0
        public static DualMatrix Identity(int rows, int columns)
        {
            if (rows < 0 || columns < 0)
            {
                throw new ArgumentOutOfRangeException();
            }

            int n = Math.Min(rows, columns);

            DualMatrix a = new DualMatrix(rows, columns);
            for (int i = 0; i < n; i++)
            {
                a[i, i] = 1.0;
            }

            return a;
        }
예제 #10
0
        public static DualMatrix Diagonal(params DualNumber[] values)
        {
            if (values == null)
            {
                throw new ArgumentNullException();
            }

            int n = values.Length;

            DualMatrix a = new DualMatrix(n, n);
            for (int i = 0; i < n; i++)
            {
                a[i, i] = values[i];
            }

            return a;
        }
        private static DualMatrix InverseDirect(int m, DualMatrix matrix, DualNumber determinant)
        {
            if (m == 1)
            {
                DualNumber a11 = matrix[0, 0];
                return new DualMatrix(new DualNumber[,] { { 1.0 / a11 } });
            }
            else if (m == 2)
            {
                DualNumber a11 = matrix[0, 0];
                DualNumber a12 = matrix[0, 1];
                DualNumber a21 = matrix[1, 0];
                DualNumber a22 = matrix[1, 1];
                return new DualMatrix(new DualNumber[,] { { a22 / determinant, -a12 / determinant }, { -a21 / determinant, a11 / determinant } });
            }
            else if (m == 3)
            {
                DualNumber a11 = matrix[0, 0];
                DualNumber a12 = matrix[0, 1];
                DualNumber a13 = matrix[0, 2];
                DualNumber a21 = matrix[1, 0];
                DualNumber a22 = matrix[1, 1];
                DualNumber a23 = matrix[1, 2];
                DualNumber a31 = matrix[2, 0];
                DualNumber a32 = matrix[2, 1];
                DualNumber a33 = matrix[2, 2];

                // Using http://mathworld.wolfram.com/MatrixInverse.html.
                return new DualMatrix(new DualNumber[,] {
                    { (a22 * a33 - a23 * a32) / determinant, (a13 * a32 - a12 * a33) / determinant, (a12 * a23 - a13 * a22) / determinant },
                    { (a23 * a31 - a21 * a33) / determinant, (a11 * a33 - a13 * a31) / determinant, (a13 * a21 - a11 * a23) / determinant },
                    { (a21 * a32 - a22 * a31) / determinant, (a12 * a31 - a11 * a32) / determinant, (a11 * a22 - a12 * a21) / determinant }
                });
            }
            else
            {
                throw new NotImplementedException();
            }
        }
예제 #12
0
        public DualMatrix SetMatrix(int row, int column, DualMatrix subMatrix)
        {
            if (row < 0 || row + subMatrix.Rows > Rows || column < 0 || column + subMatrix.Columns > Columns)
            {
                throw new ArgumentOutOfRangeException();
            }

            int n = subMatrix.Rows;
            int m = subMatrix.Columns;

            DualMatrix b = new DualMatrix(entries);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    b[row + i, column + j] = subMatrix[i, j];
                }
            }

            return b;
        }
예제 #13
0
        public DualVector(Vector values, Vector[] gradients, Vector[,] hessians)
        {
            int n = 0;

            Matrix[] matrixGradients = null;
            if (gradients != null)
            {
                n = gradients.Length;

                matrixGradients = new Matrix[n];
                for (int i = 0; i < n; i++)
                {
                    if (gradients[i] == null)
                    {
                        throw new ArgumentNullException("gradients", "The gradients must be fully specified.");
                    }

                    matrixGradients[i] = (Matrix)gradients[i];
                }
            }

            Matrix[,] matrixHessians = null;
            if (hessians != null)
            {
                if (hessians.GetLength(0) != n || hessians.GetLength(1) != n)
                {
                    throw new ArgumentException("Inconsistent number of derivatives.");
                }

                matrixHessians = new Matrix[n, n];
                for (int i = 0; i < n; i++)
                {
                    for (int j = 0; j < n; j++)
                    {
                        if (hessians[i, j] == null)
                        {
                            throw new ArgumentNullException("hessians", "The Hessians must be fully specified.");
                        }

                        matrixHessians[i, j] = (Matrix)hessians[i, j];
                    }
                }
            }

            inner = new DualMatrix((Matrix)values, matrixGradients, matrixHessians);
        }
예제 #14
0
        public static DualMatrix operator -(DualMatrix a, DualMatrix b)
        {
            int n = a.Rows;
            int m = a.Columns;

            if (b.Rows != n || b.Columns != m)
            {
                throw new ArgumentException("The matrix dimensions don't match.");
            }

            DualMatrix c = new DualMatrix(n, m);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    c[i, j] = a[i, j] - b[i, j];
                }
            }

            return c;
        }
예제 #15
0
        public static DualMatrix operator *(DualMatrix a, DualMatrix b)
        {
            int n = a.Rows;
            int m = b.Columns;
            int l = a.Columns;

            if (b.Rows != l)
            {
                throw new ArgumentException("The matrix dimensions don't match.");
            }

            DualMatrix c = new DualMatrix(n, m);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    DualNumber s = 0.0;
                    for (int k = 0; k < l; k++)
                    {
                        s += a[i, k] * b[k, j];
                    }

                    c[i, j] = s;
                }
            }

            return c;
        }
        private static DualNumber Determinant(DualMatrix matrix, int m, int n, Matrix inverse, double determinant)
        {
            if (n < 0)
            {
                return determinant;
            }

            // Compute the gradient in the first loop (not scaled by the determinant yet).
            // These are used to compute the Hessian.

            double[] gradientArray = new double[n];

            for (int i = 0; i < n; i++)
            {
                // Formula (41) in The Matrix Cookbook.

                double s = 0.0;
                for (int k = 0; k < m; k++)
                {
                    for (int l = 0; l < m; l++)
                    {
                        s += inverse[k, l] * matrix[l, k].Gradient[i];
                    }
                }
                gradientArray[i] = s;
            }

            // Compute the Hessian.

            double[] hessianArray = new double[n * (n + 1) / 2];

            for (int i = 0, h = 0; i < n; i++)
            {
                for (int j = i; j < n; j++, h++)
                {
                    // Formula (42) in The Matrix Cookbook. Also works when taking partial derivatives
                    // with respect to two different variables.

                    double s = 0.0;
                    for (int k = 0; k < m; k++)
                    {
                        for (int l = 0; l < m; l++)
                        {
                            double si = 0.0;
                            double sj = 0.0;
                            for (int q = 0; q < m; q++)
                            {
                                si += inverse[k, q] * matrix[q, l].Gradient[i];
                                sj += inverse[l, q] * matrix[q, k].Gradient[j];
                            }
                            s += inverse[k, l] * matrix[l, k].Hessian[i, j] - si * sj;
                        }
                    }
                    hessianArray[h] = determinant * (gradientArray[i] * gradientArray[j] + s);
                }

                // Final scaling of the gradient. This index is not used anymore in the loop.
                gradientArray[i] *= determinant;
            }

            // Finally create the DualNumber instance.
            return new DualNumber(determinant, gradientArray, hessianArray);
        }
        private static int GradientLength(int m, DualMatrix matrix)
        {
            int n = -1;

            for (int i = 0; i < m; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    Vector gradient = matrix[i, j].Gradient;
                    if (gradient != null)
                    {
                        if (n != -1 && gradient.Length != n)
                        {
                            throw new ArgumentException("Inconsistent number of derivatives.");
                        }

                        n = gradient.Length;
                    }
                }
            }

            return n;
        }
예제 #18
0
        public DualMatrix GetMatrix(int row, int column, int rows, int columns)
        {
            if (rows < 0 || row < 0 || row + rows > Rows || columns < 0 || column < 0 || column + columns > Columns)
            {
                throw new ArgumentOutOfRangeException();
            }

            int n = rows;
            int m = columns;

            DualMatrix a = new DualMatrix(n, m);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    a[i, j] = this[row + i, column + j];
                }
            }

            return a;
        }
 private static DualNumber DeterminantDirect(int m, DualMatrix matrix)
 {
     if (m == 1)
     {
         DualNumber a11 = matrix[0, 0];
         return a11;
     }
     else if (m == 2)
     {
         DualNumber a11 = matrix[0, 0];
         DualNumber a12 = matrix[0, 1];
         DualNumber a21 = matrix[1, 0];
         DualNumber a22 = matrix[1, 1];
         return a11 * a22 - a12 * a21;
     }
     else if (m == 3)
     {
         DualNumber a11 = matrix[0, 0];
         DualNumber a12 = matrix[0, 1];
         DualNumber a13 = matrix[0, 2];
         DualNumber a21 = matrix[1, 0];
         DualNumber a22 = matrix[1, 1];
         DualNumber a23 = matrix[1, 2];
         DualNumber a31 = matrix[2, 0];
         DualNumber a32 = matrix[2, 1];
         DualNumber a33 = matrix[2, 2];
         return a11 * a22 * a33 + a12 * a23 * a31 + a13 * a21 * a32 - a11 * a23 * a32 - a12 * a21 * a33 - a13 * a22 * a31;
     }
     else
     {
         throw new NotImplementedException();
     }
 }
예제 #20
0
        public DualMatrix SetEntry(int row, int column, DualNumber value)
        {
            if (row < 0 || row >= Rows || column < 0 || column >= Columns)
            {
                throw new ArgumentOutOfRangeException();
            }

            DualMatrix a = new DualMatrix(entries);
            a[row, column] = value;

            return a;
        }
예제 #21
0
 public static DualNumber Determinant(DualMatrix matrix)
 {
     // Use direct computation for low dimenstions; LU decomposition otherwise.
     return DualLUDecomposition.Determinant(matrix);
 }
예제 #22
0
        public static DualMatrix operator -(DualNumber t, DualMatrix a)
        {
            int n = a.Rows;
            int m = a.Columns;

            DualMatrix b = new DualMatrix(n, m);
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < m; j++)
                {
                    b[i, j] = t - a[i, j];
                }
            }

            return b;
        }
        private static DualMatrix Inverse(DualMatrix matrix, int m, int n, Matrix inverse)
        {
            if (n < 0)
            {
                // Return a matrix without derivatives information (using the implicit matrix conversion).
                return inverse;
            }

            double[,][] gradientArrays = new double[m, m][];

            // Compute all gradients in the first loop. These are used to compute the Hessian.

            for (int i0 = 0; i0 < m; i0++)
            {
                for (int j0 = 0; j0 < m; j0++)
                {
                    double[] gradientArray = new double[n];

                    for (int i = 0; i < n; i++)
                    {
                        // Formula (36) in The Matrix Cookbook.

                        double s = 0.0;
                        for (int k = 0; k < m; k++)
                        {
                            for (int l = 0; l < m; l++)
                            {
                                s += inverse[i0, k] * matrix[k, l].Gradient[i] * inverse[l, j0];
                            }
                        }
                        gradientArray[i] = -s;
                    }

                    gradientArrays[i0, j0] = gradientArray;
                }
            }

            // Compute Hessians and DualNumber instances.

            DualNumber[,] a = new DualNumber[m, m];
            for (int i0 = 0; i0 < m; i0++)
            {
                for (int j0 = 0; j0 < m; j0++)
                {
                    double[] hessianArray = new double[n * (n + 1) / 2];

                    for (int i = 0, h = 0; i < n; i++)
                    {
                        for (int j = i; j < n; j++, h++)
                        {
                            double s = 0.0;
                            for (int k = 0; k < m; k++)
                            {
                                for (int l = 0; l < m; l++)
                                {
                                    s += gradientArrays[i0, k][i] * matrix[k, l].Gradient[j] * inverse[l, j0]
                                        + inverse[i0, k] * matrix[k, l].Gradient[h] * inverse[l, j0]
                                        + inverse[i0, k] * matrix[k, l].Gradient[j] * gradientArrays[l, j0][i];
                                }
                            }
                            hessianArray[h] = -s;
                        }
                    }

                    a[i0, j0] = new DualNumber(inverse[i0, j0], gradientArrays[i0, j0], hessianArray);
                }
            }

            return new DualMatrix(a);
        }
예제 #24
0
        private DualVector(DualMatrix inner)
        {
            if (inner.Columns != 1)
            {
                throw new ArgumentException();
            }

            this.inner = inner;
        }
예제 #25
0
        public static DualMatrix Basis(int rows, int columns, int row, int column)
        {
            if (rows < 0 || row < 0 || row >= rows || columns < 0 || column < 0 || column >= columns)
            {
                throw new ArgumentOutOfRangeException();
            }

            DualMatrix a = new DualMatrix(rows, columns);
            a[row, column] = 1.0;

            return a;
        }