public void AssociatedLegendreOrthonormalityL()
        {
            // don't let l and m get too big, or numerical integration will fail due to heavily oscilatory behavior

            int[] ells = TestUtilities.GenerateIntegerValues(1, 10, 4);
            for (int ki = 0; ki < ells.Length; ki++)
            {
                int k = ells[ki];
                for (int li = 0; li <= ki; li++)
                {
                    int l = ells[li];
                    foreach (int m in TestUtilities.GenerateUniformIntegerValues(0, Math.Min(k, l), 4))
                    {
                        Func <double, double> f = delegate(double x) {
                            return(OrthogonalPolynomials.LegendreP(k, m, x) * OrthogonalPolynomials.LegendreP(l, m, x));
                        };
                        double I = FunctionMath.Integrate(f, Interval.FromEndpoints(-1.0, 1.0));

                        Console.WriteLine("k={0} l={1} m={2} I={3}", k, l, m, I);

                        if (k == l)
                        {
                            Assert.IsTrue(TestUtilities.IsNearlyEqual(
                                              I, 2.0 / (2 * k + 1) * Math.Exp(AdvancedIntegerMath.LogFactorial(l + m) - AdvancedIntegerMath.LogFactorial(l - m))
                                              ));
                        }
                        else
                        {
                            Assert.IsTrue(Math.Abs(I) < TestUtilities.TargetPrecision);
                        }
                    }
                }
            }
        }
        private double DurbinSeriesQPrime(double t)
        {
            if (t >= n)
            {
                return(0.0);
            }

            // first term
            double s = 2.0 * Math.Pow((n - t) / n, n - 1);

            // higher terms
            int jmax = (int)Math.Floor(n - t);

            if (jmax == (n - t))
            {
                jmax--;
            }
            for (int j = 1; j <= jmax; j++)
            {
                double B = Math.Exp(AdvancedIntegerMath.LogFactorial(n - 1) - AdvancedIntegerMath.LogFactorial(j) - AdvancedIntegerMath.LogFactorial(n - j));
                double C = Math.Pow((t + j) / n, j - 1) * Math.Pow((n - j - t) / n, n - j);
                double D = 1.0 + (j - 1) * t / (t + j) - (n - j) * t / (n - j - t);
                s += -2.0 * B * C * D;
            }
            return(s);
        }
Beispiel #3
0
        public int GetNext(Random rng)
        {
            while (true)
            {
                double u = rng.NextDouble() - 0.5;
                double v = rng.NextDouble();

                double us = 0.5 - Math.Abs(u);
                int    k  = (int)Math.Floor((2.0 * a / us + b) * u + lambda + 0.43);
                if (us > 0.07 && v < vr)
                {
                    return(k);
                }
                if (k < 0)
                {
                    continue;
                }
                if (us < 0.013 && v > us)
                {
                    continue;
                }
                double ai = 1.1239 + 1.1328 / (b - 3.4);
                if (Math.Log(v * ai / (a / (us * us) + b)) <= -lambda + k * lnmu - AdvancedIntegerMath.LogFactorial(k))
                {
                    return(k);
                }
            }
        }
 public void FactorialDoubleFactorialRelationship()
 {
     // n! = n!! (n-1)!!
     foreach (int n in TestUtilities.GenerateIntegerValues(1, 100, 5))
     {
         Assert.IsTrue(TestUtilities.IsNearlyEqual(
                           AdvancedIntegerMath.LogFactorial(n),
                           AdvancedIntegerMath.LogDoubleFactorial(n) + AdvancedIntegerMath.LogDoubleFactorial(n - 1)
                           ));
     }
 }
        // the chi2 test fails when the expected values of some entries are small, because the entry values are not normally distributed
        // in the 2X2 case, the probably of any given entry value can be computed; it is given by
        //        N_R1! N_R2! N_C1! N_C2!
        // P = ----------------------------
        //      N_11! N_12! N_21! N_22! N!
        // the exact test computes this probability for the actual table and for all other tables having the same row and column totals
        // the test statistic is the fraction of tables that have a lower probability than the actual table; it is uniformly distributed
        // on [0,1]. if this fraction is very small, the actual table is particularly unlikely under the null hypothesis of no correlation

        /// <summary>
        /// Performs a Fisher exact test.
        /// </summary>
        /// <returns>The results of the test. The test statistic is the summed probability of all tables exhibiting equal or stronger correlations,
        /// and its likelyhood under the null hypothesis is the (left) probability to obtain a smaller value. Note that, in this case, the test
        /// statistic itself is the likelyhood.</returns>
        /// <remarks><para>The Fisher exact test tests for correlations between row and column entries. It is a robust, non-parametric test,
        /// which, unlike the &#x3C7;<sup>2</sup> test (see <see cref="ContingencyTable.PearsonChiSquaredTest"/>), can safely be used for tables
        /// with small, even zero-valued, entries.</para>
        /// <para>The Fisher test computes, under the null hypothesis of no correlation, the exact probability of all 2 X 2 tables with the
        /// same row and column totals as the given table. It then sums the probabilities of all tables that are as or less probable than
        /// the given table. In this way it determines the total probability of obtaining a 2 X 2 table which is at least as improbable
        /// as the given one.</para>
        /// <para>The test is two-sided, i.e. when considering less probable tables it does not distinguish between tables exhibiting
        /// the same and the opposite correlation as the given one.</para>
        /// </remarks>
        /// <seealso href="http://en.wikipedia.org/wiki/Fisher_exact_test"/>
        public TestResult FisherExactTest()
        {
            // store row and column totals
            int[] R = this.RowTotals;
            int[] C = this.ColumnTotals;
            int   N = this.Total;

            // compute the critical probability
            double x =
                AdvancedIntegerMath.LogFactorial(R[0]) +
                AdvancedIntegerMath.LogFactorial(R[1]) +
                AdvancedIntegerMath.LogFactorial(C[0]) +
                AdvancedIntegerMath.LogFactorial(C[1]) -
                AdvancedIntegerMath.LogFactorial(N);
            double lnPc = x -
                          AdvancedIntegerMath.LogFactorial(this[0, 0]) -
                          AdvancedIntegerMath.LogFactorial(this[0, 1]) -
                          AdvancedIntegerMath.LogFactorial(this[1, 0]) -
                          AdvancedIntegerMath.LogFactorial(this[1, 1]);

            // compute all possible 2 X 2 matrices with these row and column totals
            // compute the total probability of getting a matrix as or less probable than the measured one
            double P = 0.0;

            int[,] test = new int[2, 2];
            int min = Math.Max(C[0] - R[1], 0);
            int max = Math.Min(R[0], C[0]);

            for (int i = min; i <= max; i++)
            {
                test[0, 0] = i;
                test[0, 1] = R[0] - i;
                test[1, 0] = C[0] - i;
                test[1, 1] = R[1] - test[1, 0];
                double lnP = x -
                             AdvancedIntegerMath.LogFactorial(test[0, 0]) -
                             AdvancedIntegerMath.LogFactorial(test[0, 1]) -
                             AdvancedIntegerMath.LogFactorial(test[1, 0]) -
                             AdvancedIntegerMath.LogFactorial(test[1, 1]);
                if (lnP <= lnPc)
                {
                    P += Math.Exp(lnP);
                }
            }

            // return the result
            return(new TestResult(P, new UniformDistribution(Interval.FromEndpoints(0.0, 1.0))));
        }
 /// <inheritdoc />
 public override double ProbabilityMass(int k)
 {
     if (k < 0)
     {
         return(0.0);
     }
     else
     {
         // these are the same expression, but the form for small arguments is faster and the form for large arguments avoids overflow
         if (k < 16)
         {
             return(Math.Exp(-mu) * MoreMath.Pow(mu, k) / AdvancedIntegerMath.Factorial(k));
         }
         else
         {
             return(Math.Exp(
                        k * Math.Log(mu) - AdvancedIntegerMath.LogFactorial(k) - mu
                        ));
         }
     }
 }
Beispiel #7
0
        private void ComputeCounts()
        {
            // our results must fit into a long, which takes us up to about n~20
            if (AdvancedIntegerMath.LogFactorial(n) > Math.Log(Int64.MaxValue))
            {
                throw new InvalidOperationException();
            }

            // pre-compute some values we will use
            int shiftIncrement = n * (n + 1) / 2;

            sMin = n * (n + 1) * (n + 2) / 6;
            sMax = n * (n + 1) * (2 * n + 1) / 6;
            //Console.WriteLine("sMin = {0} sMax = {1}", sMin, sMax);

            // to improve performance, we calculate counts only up to the middle bin and use symmetry to obtain the higher ones
            // the midpoint is of course (sMin+sMax)/2, but for even n this is a half-integer
            // since we want to include the middle bin but integer arithmetic rounds down, we
            // add one before halving; this gives the right maximum bin to compute for both even and odd n
            sMid = (sMin + sMax + 1) / 2;

            bool baseSign = (n % 2 == 0);

            // array to accumulate permanent polynomial coefficients
            // only the entries between sMin and sMax matter, as per (1) and (2) above
            long[] totalP = new long[sMid + 1];

            // as per Ryser's formula, loop over all cominations of rows
            // use b as a length 2^n bitmask indicating which columns to include in a combination
            ulong bmax = (((ulong)1) << n);

            // skip b = 0 since that means include no columns, resulting in a zero contribution

            // skip even b values as we will compute their contributions by using (3) above

            // do the b=1 case specially
            // when only one column enters, the product over all rows is a simply the monomial x^{(c+1) n n(+1) / 2}
            // knowing this, we can avoid all the multiplication to get us there
            // all the one column cases are produced by left-shifting the b=1 case
            // only those for which the power lies in [sMin,sMax] need be recorded
            int p = shiftIncrement;

            while (p < sMin)
            {
                p += shiftIncrement;
            }
            while (p <= sMid)
            {
                totalP[p] += baseSign ? -1 : 1;
                //totalP[p] += 1;
                p += shiftIncrement;
            }

            // okay, now we are ready for the remaining combinations of columns
            for (ulong b = 3; b < bmax; b += 2)
            {
                //Console.WriteLine("k={0}", k);

                // compute the row sum polynomial for the first row
                // while we are at it, we compute the sign of the combination
                // and note the degree of the polynomial as well
                long[] productP = new long[n + 1];
                //bool sign = true;
                bool sign = baseSign;
                int  d    = 0;
                for (int c = 0; c < n; c++)
                {
                    ulong bp = ((ulong)1) << c;
                    if ((b & bp) != 0)
                    {
                        /* productP[c + 1] = 1; */
                        productP[c] = 1;
                        /* d = c + 1; */
                        d    = c;
                        sign = !sign;
                    }
                }

                // row sum polynomials for higher rows are obtained from those from
                // the first row by increasing the stride. just continue to multiply
                // the product polynomial by each row sum polynomial to get the total
                // contribution of the set
                for (int r = 1; r < n; r++)
                {
                    int da = productP.Length - 1;
                    productP = LongPolynomialMultiply(productP, da, b, d, r + 1, sMid);
                }

                //LongPolynomialMath.Write(productP, 0, productP.Length-1);

                // add the contribution that particular k,
                // then the contributions from left-shifting it,
                // which as per (3) are obtained by shifting the powers by n(n+1)/2
                // for each left-shift

                /* int shift = 0; */
                int   shift = shiftIncrement;
                ulong k2    = b;
                while (k2 < bmax)
                {
                    LongPolynomialAdd(totalP, productP, shift, sMin, sMid, sign);
                    k2     = k2 << 1;
                    shift += shiftIncrement;
                }
            }

            // include the overall (-1)^n
            //if (n % 2 == 0) {
            //    LongPolynomialNegate(totalP, sMin, sMid);
            //}

            counts = new long[sMid - sMin + 1];
            Array.Copy(totalP, sMin, counts, 0, counts.Length);
            //for (int i = 0; i < counts.Length; i++) {
            //    counts[i] = totalP[sMin + i];
            //}
            //for (int i = sMin; i <= sMid; i++) {
            //    Console.WriteLine("{0} {1}", i, totalP[i]);
            //}
        }
        /// <summary>
        /// Performs a Fisher exact test.
        /// </summary>
        /// <returns>The results of the test. The test statistic is the summed probability of all tables exhibiting equal or stronger correlations,
        /// and its likelihood under the null hypothesis is the (left) probability to obtain a smaller value. Note that, in this case, the test
        /// statistic itself is the likelihood.</returns>
        /// <remarks><para>The Fisher exact test tests for correlations between row and column entries. It is a robust, non-parametric test,
        /// which, unlike the &#x3C7;<sup>2</sup> test (see <see cref="ContingencyTable{R,C}.PearsonChiSquaredTest"/>), can safely be used for tables
        /// with small, even zero-valued, entries.</para>
        /// <para>The Fisher test computes, under the null hypothesis of no correlation, the exact probability of all 2 X 2 tables with the
        /// same row and column totals as the given table. It then sums the probabilities of all tables that are as or less probable than
        /// the given table. In this way it determines the total probability of obtaining a 2 X 2 table which is at least as improbable
        /// as the given one.</para>
        /// <para>The test is two-sided, i.e. when considering less probable tables it does not distinguish between tables exhibiting
        /// the same and the opposite correlation as the given one.</para>
        /// </remarks>
        /// <seealso href="http://en.wikipedia.org/wiki/Fisher_exact_test"/>
        public TestResult FisherExactTest()
        {
            // Store row and column totals
            int[] R = new int[] { counts[0, 0] + counts[0, 1], counts[1, 0] + counts[1, 1] };
            int[] C = new int[] { counts[0, 0] + counts[1, 0], counts[0, 1] + counts[1, 1] };
            int   N = counts[0, 0] + counts[0, 1] + counts[1, 0] + counts[1, 1];

            Debug.Assert(R[0] + R[1] == N);
            Debug.Assert(C[0] + C[1] == N);

            // Compute the critical probability of the measured matrix given the marginal totals
            // and the assumption of no association.
            double x =
                AdvancedIntegerMath.LogFactorial(R[0]) +
                AdvancedIntegerMath.LogFactorial(R[1]) +
                AdvancedIntegerMath.LogFactorial(C[0]) +
                AdvancedIntegerMath.LogFactorial(C[1]) -
                AdvancedIntegerMath.LogFactorial(N);
            double lnPc = x -
                          AdvancedIntegerMath.LogFactorial(counts[0, 0]) -
                          AdvancedIntegerMath.LogFactorial(counts[0, 1]) -
                          AdvancedIntegerMath.LogFactorial(counts[1, 0]) -
                          AdvancedIntegerMath.LogFactorial(counts[1, 1]);

            // Compute all possible 2 X 2 matrices with these row and column totals.
            // Find the total probability of getting a matrix as or less probable than the measured one.
            double P = 0.0;

            int[,] test = new int[2, 2];
            int min = Math.Max(C[0] - R[1], 0);
            int max = Math.Min(R[0], C[0]);

            // If the relevant hypergeometric distribution over i is symmetric, then lnP for the i on
            // the other side is exactly equal to lnPc. But floating point noise means that it might come
            // in ever so slightly higher, causing us to incorrectly exclude that corresponding bin. This
            // caused a bug. So handle the symmetric case specially.
            if ((R[0] == R[1]) || (C[0] == C[1]))
            {
                double mid = (min + max) / 2.0;
                if (counts[0, 0] == mid)
                {
                    P = 1.0;
                }
                else
                {
                    int imax = (counts[0, 0] < mid) ? counts[0, 0] : min + (max - counts[0, 0]);
                    for (int i = min; i <= imax; i++)
                    {
                        test[0, 0] = i;
                        test[0, 1] = R[0] - i;
                        test[1, 0] = C[0] - i;
                        test[1, 1] = R[1] - test[1, 0];
                        double lnP = x -
                                     AdvancedIntegerMath.LogFactorial(test[0, 0]) -
                                     AdvancedIntegerMath.LogFactorial(test[0, 1]) -
                                     AdvancedIntegerMath.LogFactorial(test[1, 0]) -
                                     AdvancedIntegerMath.LogFactorial(test[1, 1]);
                        P += Math.Exp(lnP);
                    }
                    P *= 2.0;
                    Debug.Assert(P <= 1.0);
                }
            }
            else
            {
                for (int i = min; i <= max; i++)
                {
                    test[0, 0] = i;
                    test[0, 1] = R[0] - i;
                    test[1, 0] = C[0] - i;
                    test[1, 1] = R[1] - test[1, 0];
                    double lnP = x -
                                 AdvancedIntegerMath.LogFactorial(test[0, 0]) -
                                 AdvancedIntegerMath.LogFactorial(test[0, 1]) -
                                 AdvancedIntegerMath.LogFactorial(test[1, 0]) -
                                 AdvancedIntegerMath.LogFactorial(test[1, 1]);
                    if (lnP <= lnPc)
                    {
                        P += Math.Exp(lnP);
                    }
                }
            }

            return(new TestResult("P", P, new UniformDistribution(Interval.FromEndpoints(0.0, 1.0)), TestType.LeftTailed));
        }