Example #1
0
        public void SolveTest()
        {
            double[,] value =
            {
                {  2,  3, 0 },
                { -1,  2, 1 },
                {  0, -1, 3 }
            };

            double[,] rhs =
            {
                { 1, 2, 3 },
                { 3, 2, 1 },
                { 5, 0, 1 },
            };

            double[,] expected =
            {
                { -0.2174, -0.1739, 0.6522 },
                {  0.4783,  0.7826, 0.5652 },
                {  1.8261,  0.2609, 0.5217 },
            };

            LuDecomposition target = new LuDecomposition(value);

            double[,] actual = target.Solve(rhs);

            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.001));
        }
Example #2
0
        public void SolveTest5()
        {
            double[,] value =
            {
                { 2.1, 3.1 },
                { 1.6, 4.2 },
                { 2.1, 5.1 },
            };

            double[] rhs = { 6.1, 4.3, 2.1 };

            double[] expected = { 3.1839, -0.1891 };

            LuDecomposition target = new LuDecomposition(value);

            bool thrown = false;

            try
            {
                double[] actual = target.Solve(rhs);
            }
            catch (InvalidOperationException)
            {
                thrown = true;
            }

            Assert.IsTrue(thrown);
        }
Example #3
0
        public void SolveTest1()
        {
            double[,] value =
            {
                {  2,  3, 0 },
                { -1,  2, 1 },
                {  0, -1, 3 }
            };

            double[] rhs = { 5, 0, 1 };

            double[] expected =
            {
                1.6522,
                0.5652,
                0.5217,
            };

            var target = new LuDecomposition(value);

            double[] actual = target.Solve(rhs);
            Assert.IsTrue(Matrix.IsEqual(expected, actual, 1e-3));
            Assert.IsTrue(Matrix.IsEqual(value, target.Reverse()));

            var target2 = new JaggedLuDecomposition(value.ToJagged());

            actual = target2.Solve(rhs);
            Assert.IsTrue(Matrix.IsEqual(expected, actual, 1e-3));
            Assert.IsTrue(Matrix.IsEqual(value, target2.Reverse()));
        }
Example #4
0
        /// <summary>
        /// 三维空间中两直线的交点
        /// </summary>
        /// <returns>如果这两条射线所对应的空间直线能够相交,则返回其交点,如果不能相交,则返回 null。</returns>
        /// <remarks>
        /// 空间三维直线的参数方程为:
        ///    x=x0 + m*t;
        ///    y=y0 + n*t;
        ///    z=z0 + p*t;
        /// 其中{x0,y0,z0} 为直线中的某个点,{m,n,p}为直线的方向向量。</remarks>
        private static XYZ GetIntersectPoint(Line3D line1, Line3D line2)
        {
            // 构造一个六个方程、五个未知数x,y,z,t,k的线性方程组

            // 先用前五个方程解出对应的五个未知数
            double[][] dataA = new double[][]
            {
                new double[] { 1, 0, 0, -line1.Direction.X, 0 },
                new double[] { 0, 1, 0, -line1.Direction.Y, 0 },
                new double[] { 0, 0, 1, -line1.Direction.Z, 0 },
                new double[] { 1, 0, 0, 0, -line2.Direction.X },
                new double[] { 0, 1, 0, 0, -line2.Direction.Y },
            };

            double[][] dataB = new double[][]
            {
                new double[] { line1.Origin.X },
                new double[] { line1.Origin.Y },
                new double[] { line1.Origin.Z },
                new double[] { line2.Origin.X },
                new double[] { line2.Origin.Y },
            };

            Matrix A = new Matrix(dataA);
            Matrix b = new Matrix(dataB);

            // 通过LU上下三角分解法 求解线性方程组 Ax = b
            LuDecomposition d = new LuDecomposition(A);

            Matrix x = d.Solve(b);

            // 五个未知量 x,y,z,t,k 的值
            var col = x.GetColumn(0);

            // 将这五个变量代入第六个方程 z = z2 + p2 * k 中,
            // 如果此方程左边与右边相等,则表示两条直线有交点,否则两条直线不相交。
            var left  = col[2];
            var right = line2.Origin.Z + line2.Direction.Z * col[4];

            // 计算左右两边的相对误差
            double relative = Math.Abs((left - right) / Math.Max(left, right));

            //
            if (relative > 0.0001)
            {
                return(null);
            }
            return(relative < 0.0001 ? new XYZ(col[0], col[1], col[2]) : null);
        }
Example #5
0
        public void SolveTest4()
        {
            double[,] value =
            {
                { 2.1, 3.1 },
                { 1.6, 4.2 },
            };

            double[] rhs = { 6.1, 4.3 };

            double[] expected = { 3.1839, -0.1891 };

            LuDecomposition target = new LuDecomposition(value);

            double[] actual = target.Solve(rhs);

            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.001));
        }
Example #6
0
        public void SolveTest4()
        {
            double[,] value =
            {
                { 2.1, 3.1 },
                { 1.6, 4.2 },
            };

            double[] rhs = { 6.1, 4.3 };

            double[] expected = { 3.1839, -0.1891 };

            var target1 = new LuDecomposition(value);
            var target2 = new JaggedLuDecomposition(value.ToJagged());

            Assert.IsTrue(Matrix.IsEqual(expected, target1.Solve(rhs), 1e-3));
            Assert.IsTrue(Matrix.IsEqual(expected, target2.Solve(rhs), 1e-3));
        }
Example #7
0
        public static void m2()
        {
            double[][] dataA = new double[][]
            {
                new double[] { 0.03, 58.9 },
                new double[] { 5.31, -6.10 },
            };

            double[][] dataB = new double[][]
            {
                new double[] { 59.2 },
                new double[] { 47.0 },
            };

            Matrix A = new Matrix(dataA);
            Matrix b = new Matrix(dataB);
            // 通过LU上下三角分解法 求解线性方程组 Ax = b
            LuDecomposition d = new LuDecomposition(A);
            Matrix          x = d.Solve(b);
        }
Example #8
0
        public void InverseTestNaN()
        {
            int n = 5;

            var I = Matrix.Identity(n);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    double[,] value = Matrix.Magic(n);

                    value[i, j] = double.NaN;

                    var target = new LuDecomposition(value);
                    Assert.IsTrue(Matrix.IsEqual(target.Solve(I), target.Inverse()));

                    var target2 = new JaggedLuDecomposition(value.ToJagged());
                    Assert.IsTrue(Matrix.IsEqual(target2.Solve(I.ToJagged()), target2.Inverse()));
                }
            }
        }
        public void InverseTestNaN()
        {
            int n = 5;

            var I = Matrix.Identity(n);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    double[,] value = Matrix.Magic(n);

                    value[i, j] = double.NaN;

                    var target = new LuDecomposition(value);

                    var solution = target.Solve(I);
                    var inverse  = target.Inverse();

                    Assert.IsTrue(Matrix.IsEqual(solution, inverse));
                }
            }
        }
Example #10
0
    /// <summary>
    /// Finds the coefficients of a polynomial p(x) of degree n that fits the data,
    /// p(x(i)) to y(i), in a least squares sense. The result p is a row vector of
    /// length n+1 containing the polynomial coefficients in incremental powers.
    /// </summary>
    /// <param name="x">x axis values</param>
    /// <param name="y">y axis values</param>
    /// <param name="order">polynomial order including the constant</param>
    internal PolyFit(double[] x, double[] y, int order)
    {
        // incrememnt the order to match matlab way
        var matrixX = new double[x.Length, ++order];
        var matrixY = new double[x.Length, 1];

        if (x.Length != y.Length)
        {
            throw new ArgumentException("x and y array lengths do not match!");
        }

        // copy y matrix
        for (int i = 0; i < y.Length; i++)
        {
            matrixY[i, 0] = y[i];
        }

        // create the X matrix
        for (int row = 0; row < x.Length; row++)
        {
            var nVal = 1.0;

            for (int col = 0; col < order; col++)
            {
                matrixX[row, col] = nVal;
                nVal *= x[row];
            }
        }

        var matrixXt  = matrixX.Transpose();
        var matrixXtX = matrixXt.Product(matrixX);
        var matrixXtY = matrixXt.Product(matrixY);

        var lu = new LuDecomposition(matrixXtX);

        Coeff = lu.Solve(matrixXtY).GetColumn(0).ToArray();
    }
Example #11
0
        public void SolveTest1()
        {
            double[,] value =
            {
                {  2,  3, 0 },
                { -1,  2, 1 },
                {  0, -1, 3 }
            };

            double[] rhs = { 5, 0, 1 };

            double[] expected =
            {
                1.6522,
                0.5652,
                0.5217,
            };

            LuDecomposition target = new LuDecomposition(value);

            double[] actual = target.Solve(rhs);

            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.001));
        }
Example #12
0
        private double run(double[][] inputs, double[][] outputs)
        {
            // Regress using Lower-Bound Newton-Raphson estimation
            //
            // The main idea is to replace the Hessian matrix with a
            //   suitable lower bound. Indeed, the Hessian is lower
            //   bounded by a negative definite matrix that does not
            //   even depend on w [Krishnapuram et al].
            //
            //   - http://www.lx.it.pt/~mtf/Krishnapuram_Carin_Figueiredo_Hartemink_2005.pdf
            //


            // Initial definitions and memory allocations
            int N = inputs.Length;

            double[][] design       = new double[N][];
            double[][] coefficients = this.regression.Coefficients;

            // Compute the regression matrix
            for (int i = 0; i < inputs.Length; i++)
            {
                double[] row = design[i] = new double[M];

                row[0] = 1; // for intercept
                for (int j = 0; j < inputs[i].Length; j++)
                {
                    row[j + 1] = inputs[i][j];
                }
            }


            // Reset Hessian matrix and gradient
            for (int i = 0; i < gradient.Length; i++)
            {
                gradient[i] = 0;
            }

            if (UpdateLowerBound)
            {
                for (int i = 0; i < gradient.Length; i++)
                {
                    for (int j = 0; j < gradient.Length; j++)
                    {
                        lowerBound[i, j] = 0;
                    }
                }
            }

            // In the multinomial logistic regression, the objective
            // function is the log-likelihood function l(w). As given
            // by Krishnapuram et al and Böhning, this is a concave
            // function with Hessian given by:
            //
            //       H(w) = -sum(P(w) - p(w)p(w)')  (x)  xx'
            //      (see referenced paper for proper indices)
            //
            // In which (x) denotes the Kronocker product. By using
            // the lower bound principle, Krishnapuram has shown that
            // we can replace H(w) with a lower bound approximation B
            // which does not depend on w (eq. 8 on aforementined paper):
            //
            //      B = -(1/2) [I - 11/M]  (x)  sum(xx')
            //
            // Thus we can compute and invert this matrix only once.
            //


            // For each input sample in the dataset
            for (int i = 0; i < inputs.Length; i++)
            {
                // Grab variables related to the sample
                double[] x = design[i];
                double[] y = outputs[i];

                // Compute and estimate outputs
                this.compute(inputs[i], output);

                // Compute errors for the sample
                for (int j = 0; j < errors.Length; j++)
                {
                    errors[j] = y[j + 1] - output[j];
                }


                // Compute current gradient and Hessian
                //   We can take advantage of the block structure of the
                //   Hessian matrix and gradient vector by employing the
                //   Kronocker product. See [Böhning, 1992]

                // (Re-) Compute error gradient
                double[] g = Matrix.KroneckerProduct(errors, x);
                for (int j = 0; j < g.Length; j++)
                {
                    gradient[j] += g[j];
                }

                if (UpdateLowerBound)
                {
                    // Compute xxt matrix
                    for (int k = 0; k < x.Length; k++)
                    {
                        for (int j = 0; j < x.Length; j++)
                        {
                            xxt[k, j] = x[k] * x[j];
                        }
                    }

                    // (Re-) Compute weighted "Hessian" matrix
                    double[,] h = Matrix.KroneckerProduct(weights, xxt);
                    for (int j = 0; j < parameterCount; j++)
                    {
                        for (int k = 0; k < parameterCount; k++)
                        {
                            lowerBound[j, k] += h[j, k];
                        }
                    }
                }
            }


            if (UpdateLowerBound)
            {
                UpdateLowerBound = false;

                // Decompose to solve the linear system. Usually the hessian will
                // be invertible and LU will succeed. However, sometimes the hessian
                // may be singular and a Singular Value Decomposition may be needed.

                LuDecomposition lu = new LuDecomposition(lowerBound);

                // The SVD is very stable, but is quite expensive, being on average
                // about 10-15 times more expensive than LU decomposition. There are
                // other ways to avoid a singular Hessian. For a very interesting
                // reading on the subject, please see:
                //
                //  - Jeff Gill & Gary King, "What to Do When Your Hessian Is Not Invertible",
                //    Sociological Methods & Research, Vol 33, No. 1, August 2004, 54-87.
                //    Available in: http://gking.harvard.edu/files/help.pdf
                //

                // Moreover, the computation of the inverse is optional, as it will
                // be used only to compute the standard errors of the regression.

                if (lu.Nonsingular)
                {
                    // Solve using LU decomposition
                    deltas        = lu.Solve(gradient);
                    decomposition = lu;
                }
                else
                {
                    // Hessian Matrix is singular, try pseudo-inverse solution
                    decomposition = new SingularValueDecomposition(lowerBound);
                    deltas        = decomposition.Solve(gradient);
                }
            }
            else
            {
                deltas = decomposition.Solve(gradient);
            }


            previous = coefficients.Reshape(1);

            // Update coefficients using the calculated deltas
            for (int i = 0, k = 0; i < coefficients.Length; i++)
            {
                for (int j = 0; j < coefficients[i].Length; j++)
                {
                    coefficients[i][j] -= deltas[k++];
                }
            }

            solution = coefficients.Reshape(1);


            if (computeStandardErrors)
            {
                // Grab the regression information matrix
                double[,] inverse = decomposition.Inverse();

                // Calculate coefficients' standard errors
                double[][] standardErrors = regression.StandardErrors;
                for (int i = 0, k = 0; i < standardErrors.Length; i++)
                {
                    for (int j = 0; j < standardErrors[i].Length; j++, k++)
                    {
                        standardErrors[i][j] = Math.Sqrt(Math.Abs(inverse[k, k]));
                    }
                }
            }



            // Return the relative maximum parameter change
            for (int i = 0; i < deltas.Length; i++)
            {
                deltas[i] = Math.Abs(deltas[i]) / Math.Abs(previous[i]);
            }

            return(Matrix.Max(deltas));
        }
Example #13
0
        /// <summary>
        /// Compute the Thin Plate Spline of the image, return a 2D tab
        /// </summary>
        /// <param name="control_points">Control points  </param>    
        /// <param name="input">Input image to get the dim xy</param>
        public double[,] calc_tps(List<cPoint3D> control_points, cDRC_Region AssociatedRegion, double Regularization)
        {
            int p = control_points.Count;
            if (p < 3) return null;
            double[,] grid = new double[AssociatedRegion.SizeX, AssociatedRegion.SizeY];
            Matrix mtx_l = new Matrix(p + 3, p + 3);
            Matrix mtx_v = new Matrix(p + 3, 1);
            Matrix mtx_orig_k = new Matrix(p, p);
            double a = 0.0;
            for (int i = 0; i < p; ++i)
            {
                for (int j = i + 1; j < p; ++j)
                {
                    cPoint3D pt_i = new cPoint3D(control_points[i].X, control_points[i].Y, control_points[i].Z);
                    cPoint3D pt_j = new cPoint3D(control_points[j].X, control_points[j].Y, control_points[j].Z);

                    pt_i.Y = pt_j.Y = 0;

                    //double elen = Math.Sqrt((pt_i.X - pt_j.X) * (pt_i.X - pt_j.X) + (pt_i.Z - pt_j.Z) * (pt_i.Z - pt_j.Z));
                    double elen = pt_i.DistTo(pt_j);
                    mtx_l[i, j] = mtx_l[j, i] = mtx_orig_k[i, j] = mtx_orig_k[j, i] = tps_base_func(elen);
                    a += elen * 2; // same for upper & lower tri
                }
            }
            a /= (double)(p * p);
            //regularization = 0.3f;
            //Fill the rest of L
            for (int i = 0; i < p; ++i)
            {
                //diagonal: reqularization parameters (lambda * a^2)

                mtx_l[i, i] = mtx_orig_k[i, i] = Regularization * (a * a);

                // P (p x 3, upper right)
                mtx_l[i, p + 0] = 1.0;
                mtx_l[i, p + 1] = control_points[i].X;
                mtx_l[i, p + 2] = control_points[i].Z;

                // P transposed (3 x p, bottom left)
                mtx_l[p + 0, i] = 1.0;
                mtx_l[p + 1, i] = control_points[i].X;
                mtx_l[p + 2, i] = control_points[i].Z;
            }
            // O (3 x 3, lower right)
            for (int i = p; i < p + 3; ++i)
                for (int j = p; j < p + 3; ++j)
                    mtx_l[i, j] = 0.0;

            // Fill the right hand vector V
            for (int i = 0; i < p; ++i)
                mtx_v[i, 0] = control_points[i].Y;

            mtx_v[p + 0, 0] = mtx_v[p + 1, 0] = mtx_v[p + 2, 0] = 0.0;
            // Solve the linear system "inplace"
            Matrix mtx_v_res = new Matrix(p + 3, 1);

            LuDecomposition ty = new LuDecomposition(mtx_l);

            mtx_v_res = ty.Solve(mtx_v);
            if (mtx_v_res == null)
            {
                return null;
            }

            // Interpolate grid heights
            for (int x = 0; x < AssociatedRegion.SizeX; ++x)
            {
                for (int z = 0; z < AssociatedRegion.SizeY; ++z)
                {

                    //float x = 0f; float z = 0.5f;
                    double h = mtx_v_res[p + 0, 0] + mtx_v_res[p + 1, 0] * (float)x / (float)AssociatedRegion.SizeX + mtx_v_res[p + 2, 0] * (float)z / (float)AssociatedRegion.SizeY;
                    //double h = mtx_v[p + 0, 0] + mtx_v[p + 1, 0] * (float)x + mtx_v[p + 2, 0] * (float)z ;
                    cPoint3D pt_ia;
                    cPoint3D pt_cur = new cPoint3D((float)x / (float)AssociatedRegion.SizeX, 0, (float)z / (float)AssociatedRegion.SizeY);
                    //Vector3 pt_cur = new Vector3((float)x , 0, (float)z);
                    for (int i = 0; i < p; ++i)
                    {
                        pt_ia = control_points[i];
                        pt_ia.Y = 0;
                        h += mtx_v_res[i, 0] * tps_base_func(pt_ia.DistTo(pt_cur));
                    }

                    grid[x, z] = h;
                }
            }
            // Calc bending energy
            Matrix w = new Matrix(p, 1);
            for (int i = 0; i < p; ++i)
                w[i, 0] = mtx_v_res[i, 0];

            Matrix be;

            be = Matrix.Multiply(Matrix.Multiply(w.Transpose(), mtx_orig_k), w);
            bending_energy = be[0, 0];

            Console.WriteLine("be= " + be[0, 0]);
            return grid;
        }
Example #14
0
        public static CubicBezier[] BuildC2Spline(Vector2[] pts, Vector2?m0, Vector2?mn, double tension)
        {
            if (pts.Length < 2)
            {
                throw new ArgumentException("There must be at least 2 points to construct cardinal spline", "pts");
            }

            // compute reasonable starting and ending tangents if not supplied
            if (m0 == null)
            {
                m0 = tension * (pts[1] - pts[0]);
            }

            if (mn == null)
            {
                mn = tension * (pts[pts.Length - 1] - pts[pts.Length - 2]);
            }

            if (pts.Length == 2)
            {
                return(new CubicBezier[] { CubicBezier.FromCubicHermite(pts[0], m0.Value, pts[1], mn.Value) });
            }

            int n = pts.Length - 1;

            // we have > 2 points, so we will have n-1 beziers
            CubicBezier[] beziers = new CubicBezier[n];

            // build up constraint matrix
            Matrix A = new Matrix(2 * n, 2 * n, 0);

            Matrix b = new Matrix(2 * n, 2);

            // matrix row index value
            int idx = 0;

            // add starting/ending tangent constraint
            Vector2 p01 = m0.Value / 3.0 + pts[0];

            A[idx, 0] = 1;
            b[idx, 0] = p01.X; b[idx, 1] = p01.Y;
            idx++;

            Vector2 pn2 = -mn.Value / 3.0 + pts[n];

            A[idx, 2 * n - 1] = 1;
            b[idx, 0]         = pn2.X; b[idx, 1] = pn2.Y;
            idx++;

            // add C1 constraints
            for (int i = 0; i < n - 1; i++)
            {
                A[idx, i * 2 + 1]   = 1;
                A[idx, (i + 1) * 2] = 1;
                b[idx, 0]           = pts[i + 1].X * 2; b[idx, 1] = pts[i + 1].Y * 2;
                idx++;
            }

            // add C2 constraints
            for (int i = 0; i < n - 1; i++)
            {
                A[idx, i * 2]           = 1;
                A[idx, i * 2 + 1]       = -2;
                A[idx, (i + 1) * 2]     = 2;
                A[idx, (i + 1) * 2 + 1] = -1;
                b[idx, 0] = 0; b[idx, 1] = 0;
                idx++;
            }

            // build the LUDecomposition of A to solve system A*P = b;
            LuDecomposition lu = new LuDecomposition(A);
            Matrix          P  = lu.Solve(b);

            // work back the Parameters
            for (int i = 0; i < n; i++)
            {
                beziers[i] = new CubicBezier(pts[i], new Vector2(P[2 * i, 0], P[2 * i, 1]), new Vector2(P[2 * i + 1, 0], P[2 * i + 1, 1]), pts[i + 1]);
            }

            return(beziers);
        }
Example #15
0
        /// <summary>
        ///   Runs one iteration of the Reweighted Least Squares algorithm.
        /// </summary>
        /// <param name="inputs">The input data.</param>
        /// <param name="outputs">The outputs associated with each input vector.</param>
        /// <returns>The maximum relative change in the parameters after the iteration.</returns>
        ///
        public double Run(double[][] inputs, double[] outputs)
        {
            // Regress using Iteratively Reweighted Least Squares estimation.

            // References:
            //  - Bishop, Christopher M.; Pattern Recognition
            //    and Machine Learning. Springer; 1st ed. 2006.


            // Initial definitions and memory allocations
            int N = inputs.Length;

            double[][] design       = new double[N][];
            double[]   errors       = new double[N];
            double[]   weights      = new double[N];
            double[]   coefficients = this.regression.Coefficients;
            double[]   deltas;

            // Compute the regression matrix
            for (int i = 0; i < inputs.Length; i++)
            {
                double[] row = design[i] = new double[parameterCount];

                row[0] = 1; // for intercept
                for (int j = 0; j < inputs[i].Length; j++)
                {
                    row[j + 1] = inputs[i][j];
                }
            }


            // Compute errors and weighing matrix
            for (int i = 0; i < inputs.Length; i++)
            {
                double y = regression.Compute(inputs[i]);

                // Calculate error vector
                errors[i] = y - outputs[i];

                // Calculate weighting matrix
                weights[i] = y * (1.0 - y);
            }


            // Reset Hessian matrix and gradient
            for (int i = 0; i < gradient.Length; i++)
            {
                gradient[i] = 0;
                for (int j = 0; j < gradient.Length; j++)
                {
                    hessian[i, j] = 0;
                }
            }


            // (Re-) Compute error gradient
            for (int j = 0; j < design.Length; j++)
            {
                for (int i = 0; i < gradient.Length; i++)
                {
                    gradient[i] += design[j][i] * errors[j];
                }
            }

            // (Re-) Compute weighted "Hessian" matrix
            for (int k = 0; k < weights.Length; k++)
            {
                double[] rk = design[k];

                for (int j = 0; j < rk.Length; j++)
                {
                    for (int i = 0; i < rk.Length; i++)
                    {
                        hessian[j, i] += rk[i] * rk[j] * weights[k];
                    }
                }
            }


            // Decompose to solve the linear system. Usually the hessian will
            // be invertible and LU will succeed. However, sometimes the hessian
            // may be singular and a Singular Value Decomposition may be needed.

            LuDecomposition lu = new LuDecomposition(hessian);

            // The SVD is very stable, but is quite expensive, being on average
            // about 10-15 times more expensive than LU decomposition. There are
            // other ways to avoid a singular Hessian. For a very interesting
            // reading on the subject, please see:
            //
            //  - Jeff Gill & Gary King, "What to Do When Your Hessian Is Not Invertible",
            //    Sociological Methods & Research, Vol 33, No. 1, August 2004, 54-87.
            //    Available in: http://gking.harvard.edu/files/help.pdf
            //

            // Moreover, the computation of the inverse is optional, as it will
            // be used only to compute the standard errors of the regression.

            if (lu.Nonsingular)
            {
                // Solve using LU decomposition
                deltas        = lu.Solve(gradient);
                decomposition = lu;
            }
            else
            {
                // Hessian Matrix is singular, try pseudo-inverse solution
                decomposition = new SingularValueDecomposition(hessian);
                deltas        = decomposition.Solve(gradient);
            }

            previous = (double[])coefficients.Clone();

            // Update coefficients using the calculated deltas
            for (int i = 0; i < coefficients.Length; i++)
            {
                coefficients[i] -= deltas[i];
            }


            if (computeStandardErrors)
            {
                // Grab the regression information matrix
                double[,] inverse = decomposition.Inverse();

                // Calculate coefficients' standard errors
                double[] standardErrors = regression.StandardErrors;
                for (int i = 0; i < standardErrors.Length; i++)
                {
                    standardErrors[i] = Math.Sqrt(inverse[i, i]);
                }
            }


            // Return the relative maximum parameter change
            for (int i = 0; i < deltas.Length; i++)
            {
                deltas[i] = Math.Abs(deltas[i]) / Math.Abs(previous[i]);
            }

            return(Matrix.Max(deltas));
        }
Example #16
0
        /// <summary>
        ///   Iterates one pass of the optimization algorithm trying to find
        ///   the best regression coefficients for the logistic model.
        /// </summary>
        /// <remarks>
        ///   An iterative Newton-Raphson algorithm is used to calculate
        ///   the maximum likelihood values of the parameters.  This procedure
        ///   uses the partial second derivatives of the parameters in the
        ///   Hessian matrix to guide incremental parameter changes in an effort
        ///   to maximize the log likelihood value for the likelihood function.
        /// </remarks>
        /// <returns>
        ///   The absolute value of the largest parameter change.
        /// </returns>
        public double Regress(double[][] input, double[] output)
        {
            // Regress using Iterative Reweighted Least Squares estimation.

            // Initial definitions and memory allocations
            int N = input.Length;
            int M = this.Coefficients.Length;

            double[,] regression = new double[N, M];
            double[,] hessian    = new double[M, M];
            double[,] inverse;
            double[] gradient = new double[M];
            double[] errors   = new double[N];
            double[] R        = new double[N];
            double[] deltas;


            // Compute the regression matrix, errors and diagonal
            for (int i = 0; i < N; i++)
            {
                double y = this.Compute(input[i]);
                double o = output[i];

                // Calculate error vector
                errors[i] = y - o;

                // Calculate R diagonal
                R[i] = y * (1.0 - y);

                // Compute the regression matrix
                regression[i, 0] = 1;
                for (int j = 1; j < M; j++)
                {
                    regression[i, j] = input[i][j - 1];
                }
            }


            // Compute error gradient and "Hessian" matrix (with diagonal R)
            for (int i = 0; i < M; i++)
            {
                // Compute error gradient
                for (int j = 0; j < N; j++)
                {
                    gradient[i] += regression[j, i] * errors[j];
                }

                // Compute "Hessian" matrix (regression'*R*regression)
                for (int j = 0; j < M; j++)
                {
                    for (int k = 0; k < N; k++)
                    {
                        hessian[j, i] += regression[k, i] * (R[k] * regression[k, j]);
                    }
                }
            }


            // Decompose to solve the linear system. Usually the hessian will
            // be invertible and LU will succeed. However, sometimes the hessian
            // may be singular and a Singular Value Decomposition may be needed.

            LuDecomposition lu = new LuDecomposition(hessian);

            // The SVD is very stable, but is quite expensive, being on average
            // about 10-15 times more expensive than LU decomposition. There are
            // other ways to avoid a singular Hessian. For a very interesting
            // reading on the subject, please see:
            //
            //  - Jeff Gill & Gary King, "What to Do When Your Hessian Is Not Invertible",
            //    Sociological Methods & Research, Vol 33, No. 1, August 2004, 54-87.
            //    Available in: http://gking.harvard.edu/files/help.pdf
            //

            // Moreover, the computation of the inverse is optional, as it will
            // be used only to compute the standard errors of the regression.

            if (lu.Nonsingular)
            {
                // Solve using LU decomposition
                deltas  = lu.Solve(gradient);
                inverse = lu.Inverse(); // optional
            }
            else
            {
                // Hessian Matrix is singular, try pseudo-inverse solution
                SingularValueDecomposition svd = new SingularValueDecomposition(hessian);
                deltas  = svd.Solve(gradient);
                inverse = svd.Inverse(); // optional
            }


            // Update coefficients using the calculated deltas
            for (int i = 0; i < coefficients.Length; i++)
            {
                this.coefficients[i] -= deltas[i];
            }

            // Calculate Coefficients standard errors (optional)
            for (int i = 0; i < standardErrors.Length; i++)
            {
                standardErrors[i] = System.Math.Sqrt(inverse[i, i]);
            }


            // Return the absolute value of the largest parameter change
            return(Matrix.Max(Matrix.Abs(deltas)));
        }