You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ps...@apache.org on 2013/10/20 22:42:42 UTC

svn commit: r1533974 - in /commons/proper/math/trunk: ./ src/changes/ src/main/java/org/apache/commons/math3/distribution/ src/test/java/org/apache/commons/math3/distribution/

Author: psteitz
Date: Sun Oct 20 20:42:41 2013
New Revision: 1533974

URL: http://svn.apache.org/r1533974
Log:
Added logDensity methods to AbstractReal/IntegerDistribution with naive default implementations and improved implementations for some current distributions.
JIRA: MATH-1039
Patch provided by Aleksei Dievskii

Modified:
    commons/proper/math/trunk/pom.xml
    commons/proper/math/trunk/src/changes/changes.xml
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractIntegerDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractRealDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BetaDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BinomialDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ChiSquaredDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ExponentialDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/FDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GammaDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GeometricDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/HypergeometricDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LevyDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LogNormalDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/NormalDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ParetoDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PascalDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PoissonDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/TDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/WeibullDistribution.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ZipfDistribution.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/IntegerDistributionAbstractTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/LevyDistributionTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/PoissonDistributionTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/RealDistributionAbstractTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/ZipfDistributionTest.java

Modified: commons/proper/math/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/pom.xml?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/pom.xml (original)
+++ commons/proper/math/trunk/pom.xml Sun Oct 20 20:42:41 2013
@@ -181,6 +181,9 @@
       <name>Larry Diamond</name>
     </contributor>
     <contributor>
+      <name>Aleksei Dievskii</name>
+    </contributor>
+    <contributor>
       <name>Rodrigo di Lorenzo Lopes</name>
     </contributor>
     <contributor>

Modified: commons/proper/math/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/changes/changes.xml?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/changes/changes.xml (original)
+++ commons/proper/math/trunk/src/changes/changes.xml Sun Oct 20 20:42:41 2013
@@ -51,6 +51,10 @@ If the output is not quite correct, chec
   </properties>
   <body>
     <release version="x.y" date="TBD" description="TBD">
+      <action dev="psteitz" type="update" issue="MATH-1039" due-to="Aleksei Dievskii">
+        Added logDensity methods to AbstractReal/IntegerDistribution with naive default
+        implementations and improved implementations for some current distributions.
+      </action>
       <action dev="psteitz" type="add" issue="MATH-1038" due-to="Thorsten Schaefer">
         Added ConfidenceInterval class and BinomialConfidenceInterval providing several
         estimators for confidence intervals for binomial probabilities.

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractIntegerDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractIntegerDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractIntegerDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractIntegerDistribution.java Sun Oct 20 20:42:41 2013
@@ -232,4 +232,23 @@ public abstract class AbstractIntegerDis
         }
         return result;
     }
+
+    /**
+     * For a random variable {@code X} whose values are distributed according to
+     * this distribution, this method returns {@code log(P(X = x))}, where
+     * {@code log} is the natural logarithm. In other words, this method
+     * represents the logarithm of the probability mass function (PMF) for the
+     * distribution. Note that due to the floating point precision and
+     * under/overflow issues, this method will for some distributions be more
+     * precise and faster than computing the logarithm of
+     * {@link #probability(int)}.
+     * <p>
+     * The default implementation simply computes the logarithm of {@code probability(x)}.</p>
+     *
+     * @param x the point at which the PMF is evaluated
+     * @return the logarithm of the value of the probability mass function at {@code x}
+     */
+    public double logProbability(int x) {
+        return FastMath.log(probability(x));
+    }
 }

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractRealDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractRealDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractRealDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/AbstractRealDistribution.java Sun Oct 20 20:42:41 2013
@@ -286,5 +286,23 @@ implements RealDistribution, Serializabl
     public double probability(double x) {
         return 0d;
     }
+
+    /**
+     * Returns the natural logarithm of the probability density function (PDF) of this distribution
+     * evaluated at the specified point {@code x}. In general, the PDF is the derivative of the
+     * {@link #cumulativeProbability(double) CDF}. If the derivative does not exist at {@code x},
+     * then an appropriate replacement should be returned, e.g. {@code Double.POSITIVE_INFINITY},
+     * {@code Double.NaN}, or the limit inferior or limit superior of the difference quotient. Note
+     * that due to the floating point precision and under/overflow issues, this method will for some
+     * distributions be more precise and faster than computing the logarithm of
+     * {@link #density(double)}. The default implementation simply computes the logarithm of
+     * {@code density(x)}.
+     *
+     * @param x the point at which the PDF is evaluated
+     * @return the logarithm of the value of the probability density function at point {@code x}
+     */
+    public double logDensity(double x) {
+        return FastMath.log(density(x));
+    }
 }
 

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BetaDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BetaDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BetaDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BetaDistribution.java Sun Oct 20 20:42:41 2013
@@ -156,6 +156,29 @@ public class BetaDistribution extends Ab
         }
     }
 
+    /** {@inheritDoc} **/
+    @Override
+    public double logDensity(double x) {
+        recomputeZ();
+        if (x < 0 || x > 1) {
+            return Double.NEGATIVE_INFINITY;
+        } else if (x == 0) {
+            if (alpha < 1) {
+                throw new NumberIsTooSmallException(LocalizedFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_0_FOR_SOME_ALPHA, alpha, 1, false);
+            }
+            return Double.NEGATIVE_INFINITY;
+        } else if (x == 1) {
+            if (beta < 1) {
+                throw new NumberIsTooSmallException(LocalizedFormats.CANNOT_COMPUTE_BETA_DENSITY_AT_1_FOR_SOME_BETA, beta, 1, false);
+            }
+            return Double.NEGATIVE_INFINITY;
+        } else {
+            double logX = FastMath.log(x);
+            double log1mX = FastMath.log1p(-x);
+            return (alpha - 1) * logX + (beta - 1) * log1mX - z;
+        }
+    }
+
     /** {@inheritDoc} */
     public double cumulativeProbability(double x)  {
         if (x <= 0) {

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BinomialDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BinomialDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BinomialDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/BinomialDistribution.java Sun Oct 20 20:42:41 2013
@@ -110,6 +110,20 @@ public class BinomialDistribution extend
         return ret;
     }
 
+    /** {@inheritDoc} **/
+    @Override
+    public double logProbability(int x) {
+        double ret;
+        if (x < 0 || x > numberOfTrials) {
+            ret = Double.NEGATIVE_INFINITY;
+        } else {
+            ret = SaddlePointExpansion.logBinomialProbability(x,
+                    numberOfTrials, probabilityOfSuccess,
+                    1.0 - probabilityOfSuccess);
+        }
+        return ret;
+    }
+
     /** {@inheritDoc} */
     public double cumulativeProbability(int x) {
         double ret;

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ChiSquaredDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ChiSquaredDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ChiSquaredDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ChiSquaredDistribution.java Sun Oct 20 20:42:41 2013
@@ -108,6 +108,12 @@ public class ChiSquaredDistribution exte
         return gamma.density(x);
     }
 
+    /** {@inheritDoc} **/
+    @Override
+    public double logDensity(double x) {
+        return gamma.logDensity(x);
+    }
+
     /** {@inheritDoc} */
     public double cumulativeProbability(double x)  {
         return gamma.cumulativeProbability(x);

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ExponentialDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ExponentialDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ExponentialDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ExponentialDistribution.java Sun Oct 20 20:42:41 2013
@@ -56,6 +56,8 @@ public class ExponentialDistribution ext
     private static final double[] EXPONENTIAL_SA_QI;
     /** The mean of this distribution. */
     private final double mean;
+    /** The logarithm of the mean, stored to reduce computing time. **/
+    private final double logMean;
     /** Inverse cumulative probability accuracy. */
     private final double solverAbsoluteAccuracy;
 
@@ -144,6 +146,7 @@ public class ExponentialDistribution ext
             throw new NotStrictlyPositiveException(LocalizedFormats.MEAN, mean);
         }
         this.mean = mean;
+        logMean = FastMath.log(mean);
         solverAbsoluteAccuracy = inverseCumAccuracy;
     }
 
@@ -164,6 +167,12 @@ public class ExponentialDistribution ext
         return FastMath.exp(-x / mean) / mean;
     }
 
+    /** {@inheritDoc} **/
+    @Override
+    public double logDensity(double x) {
+        return -x / mean - logMean;
+    }
+
     /**
      * {@inheritDoc}
      *

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/FDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/FDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/FDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/FDistribution.java Sun Oct 20 20:42:41 2013
@@ -154,6 +154,21 @@ public class FDistribution extends Abstr
                             Beta.logBeta(nhalf, mhalf));
     }
 
+    /** {@inheritDoc} **/
+    @Override
+    public double logDensity(double x) {
+        final double nhalf = numeratorDegreesOfFreedom / 2;
+        final double mhalf = denominatorDegreesOfFreedom / 2;
+        final double logx = FastMath.log(x);
+        final double logn = FastMath.log(numeratorDegreesOfFreedom);
+        final double logm = FastMath.log(denominatorDegreesOfFreedom);
+        final double lognxm = FastMath.log(numeratorDegreesOfFreedom * x +
+                denominatorDegreesOfFreedom);
+        return nhalf * logn + nhalf * logx - logx +
+               mhalf * logm - nhalf * lognxm - mhalf * lognxm -
+               Beta.logBeta(nhalf, mhalf);
+    }
+
     /**
      * {@inheritDoc}
      *

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GammaDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GammaDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GammaDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GammaDistribution.java Sun Oct 20 20:42:41 2013
@@ -58,6 +58,15 @@ public class GammaDistribution extends A
     private final double densityPrefactor1;
     /**
      * The constant value of
+     * {@code log(shape / scale * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape))},
+     * where {@code L(shape)} is the Lanczos approximation returned by
+     * {@link Gamma#lanczos(double)}. This prefactor is used in
+     * {@link #logDensity(double)}, when no overflow occurs with the natural
+     * calculation.
+     */
+    private final double logDensityPrefactor1;
+    /**
+     * The constant value of
      * {@code shape * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape)},
      * where {@code L(shape)} is the Lanczos approximation returned by
      * {@link Gamma#lanczos(double)}. This prefactor is used in
@@ -66,6 +75,15 @@ public class GammaDistribution extends A
      */
     private final double densityPrefactor2;
     /**
+     * The constant value of
+     * {@code log(shape * sqrt(e / (2 * pi * (shape + g + 0.5))) / L(shape))},
+     * where {@code L(shape)} is the Lanczos approximation returned by
+     * {@link Gamma#lanczos(double)}. This prefactor is used in
+     * {@link #logDensity(double)}, when overflow occurs with the natural
+     * calculation.
+     */
+    private final double logDensityPrefactor2;
+    /**
      * Lower bound on {@code y = x / scale} for the selection of the computation
      * method in {@link #density(double)}. For {@code y <= minY}, the natural
      * calculation overflows.
@@ -159,9 +177,14 @@ public class GammaDistribution extends A
         this.shiftedShape = shape + Gamma.LANCZOS_G + 0.5;
         final double aux = FastMath.E / (2.0 * FastMath.PI * shiftedShape);
         this.densityPrefactor2 = shape * FastMath.sqrt(aux) / Gamma.lanczos(shape);
+        this.logDensityPrefactor2 = FastMath.log(shape) + 0.5 * FastMath.log(aux) -
+                                    FastMath.log(Gamma.lanczos(shape));
         this.densityPrefactor1 = this.densityPrefactor2 / scale *
                 FastMath.pow(shiftedShape, -shape) *
                 FastMath.exp(shape + Gamma.LANCZOS_G);
+        this.logDensityPrefactor1 = this.logDensityPrefactor2 - FastMath.log(scale) -
+                FastMath.log(shiftedShape) * shape +
+                shape + Gamma.LANCZOS_G;
         this.minY = shape + Gamma.LANCZOS_G - FastMath.log(Double.MAX_VALUE);
         this.maxLogY = FastMath.log(Double.MAX_VALUE) / (shape - 1.0);
     }
@@ -271,6 +294,32 @@ public class GammaDistribution extends A
                 FastMath.pow(y, shape - 1);
     }
 
+    /** {@inheritDoc} **/
+    @Override
+    public double logDensity(double x) {
+       /* see the comment in {@link #density(double)} for computation details
+        */
+        if (x < 0) {
+            return Double.NEGATIVE_INFINITY;
+        }
+        final double y = x / scale;
+        if ((y <= minY) || (FastMath.log(y) >= maxLogY)) {
+            /*
+             * Overflow.
+             */
+            final double aux1 = (y - shiftedShape) / shiftedShape;
+            final double aux2 = shape * (FastMath.log1p(aux1) - aux1);
+            final double aux3 = -y * (Gamma.LANCZOS_G + 0.5) / shiftedShape +
+                    Gamma.LANCZOS_G + aux2;
+            return logDensityPrefactor2 - FastMath.log(x) + aux3;
+        }
+        /*
+         * Natural calculation.
+         */
+        return logDensityPrefactor1  - y +
+                FastMath.log(y) * (shape - 1);
+    }
+
     /**
      * {@inheritDoc}
      *

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GeometricDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GeometricDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GeometricDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/GeometricDistribution.java Sun Oct 20 20:42:41 2013
@@ -86,6 +86,19 @@ public class GeometricDistribution exten
     }
 
     /** {@inheritDoc} */
+    @Override
+    public double logProbability(int x) {
+        double ret;
+        if (x < 0) {
+            ret = Double.NEGATIVE_INFINITY;
+        } else {
+            final double p = probabilityOfSuccess;
+            ret = x * FastMath.log1p(-p) + FastMath.log(p);
+        }
+        return ret;
+    }
+
+    /** {@inheritDoc} */
     public double cumulativeProbability(int x) {
         double ret;
         if (x < 0) {

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/HypergeometricDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/HypergeometricDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/HypergeometricDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/HypergeometricDistribution.java Sun Oct 20 20:42:41 2013
@@ -214,6 +214,30 @@ public class HypergeometricDistribution 
         return ret;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public double logProbability(int x) {
+        double ret;
+
+        int[] domain = getDomain(populationSize, numberOfSuccesses, sampleSize);
+        if (x < domain[0] || x > domain[1]) {
+            ret = Double.NEGATIVE_INFINITY;
+        } else {
+            double p = (double) sampleSize / (double) populationSize;
+            double q = (double) (populationSize - sampleSize) / (double) populationSize;
+            double p1 = SaddlePointExpansion.logBinomialProbability(x,
+                    numberOfSuccesses, p, q);
+            double p2 =
+                    SaddlePointExpansion.logBinomialProbability(sampleSize - x,
+                            populationSize - numberOfSuccesses, p, q);
+            double p3 =
+                    SaddlePointExpansion.logBinomialProbability(sampleSize, populationSize, p, q);
+            ret = p1 + p2 - p3;
+        }
+
+        return ret;
+    }
+
     /**
      * For this distribution, {@code X}, this method returns {@code P(X >= x)}.
      *

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LevyDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LevyDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LevyDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LevyDistribution.java Sun Oct 20 20:42:41 2013
@@ -80,6 +80,21 @@ public class LevyDistribution extends Ab
     }
 
     /** {@inheritDoc}
+     *
+     * See documentation of {@link #density(double)} for computation details.
+     */
+    @Override
+    public double logDensity(double x) {
+        if (x < mu) {
+            return Double.NaN;
+        }
+
+        final double delta = x - mu;
+        final double f     = halfC / delta;
+        return 0.5 * FastMath.log(f / FastMath.PI) - f - FastMath.log(delta);
+    }
+
+    /** {@inheritDoc}
      * <p>
      * From Wikipedia: the cumulative distribution function is
      * </p>

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LogNormalDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LogNormalDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LogNormalDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/LogNormalDistribution.java Sun Oct 20 20:42:41 2013
@@ -71,6 +71,8 @@ public class LogNormalDistribution exten
 
     /** The shape parameter of this distribution. */
     private final double shape;
+    /** The value of {@code log(shape) + 0.5 * log(2*PI)} stored for faster computation. */
+    private final double logShapePlusHalfLog2Pi;
 
     /** Inverse cumulative probability accuracy. */
     private final double solverAbsoluteAccuracy;
@@ -149,6 +151,7 @@ public class LogNormalDistribution exten
 
         this.scale = scale;
         this.shape = shape;
+        this.logShapePlusHalfLog2Pi = FastMath.log(shape) + 0.5 * FastMath.log(2 * FastMath.PI);
         this.solverAbsoluteAccuracy = inverseCumAccuracy;
     }
 
@@ -190,6 +193,21 @@ public class LogNormalDistribution exten
         return FastMath.exp(-0.5 * x1 * x1) / (shape * SQRT2PI * x);
     }
 
+    /** {@inheritDoc}
+     *
+     * See documentation of {@link #density(double)} for computation details.
+     */
+    @Override
+    public double logDensity(double x) {
+        if (x <= 0) {
+            return Double.NEGATIVE_INFINITY;
+        }
+        final double logX = FastMath.log(x);
+        final double x0 = logX - scale;
+        final double x1 = x0 / shape;
+        return -0.5 * x1 * x1 - (logShapePlusHalfLog2Pi + logX);
+    }
+
     /**
      * {@inheritDoc}
      *

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/NormalDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/NormalDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/NormalDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/NormalDistribution.java Sun Oct 20 20:42:41 2013
@@ -49,6 +49,8 @@ public class NormalDistribution extends 
     private final double mean;
     /** Standard deviation of this distribution. */
     private final double standardDeviation;
+    /** The value of {@code log(sd) + 0.5*log(2*pi)} stored for faster computation. */
+    private final double logStandardDeviationPlusHalfLog2Pi;
     /** Inverse cumulative probability accuracy. */
     private final double solverAbsoluteAccuracy;
 
@@ -124,6 +126,7 @@ public class NormalDistribution extends 
 
         this.mean = mean;
         standardDeviation = sd;
+        logStandardDeviationPlusHalfLog2Pi = FastMath.log(sd) + 0.5 * FastMath.log(2 * FastMath.PI);
         solverAbsoluteAccuracy = inverseCumAccuracy;
     }
 
@@ -152,6 +155,13 @@ public class NormalDistribution extends 
         return FastMath.exp(-0.5 * x1 * x1) / (standardDeviation * SQRT2PI);
     }
 
+    /** {@inheritDoc} */
+    public double logDensity(double x) {
+        final double x0 = x - mean;
+        final double x1 = x0 / standardDeviation;
+        return -0.5 * x1 * x1 - logStandardDeviationPlusHalfLog2Pi;
+    }
+
     /**
      * {@inheritDoc}
      *

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ParetoDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ParetoDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ParetoDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ParetoDistribution.java Sun Oct 20 20:42:41 2013
@@ -174,6 +174,18 @@ public class ParetoDistribution extends 
         return FastMath.pow(scale, shape) / FastMath.pow(x, shape + 1) * shape;
     }
 
+    /** {@inheritDoc}
+     *
+     * See documentation of {@link #density(double)} for computation details.
+     */
+    @Override
+    public double logDensity(double x) {
+        if (x < scale) {
+            return Double.NEGATIVE_INFINITY;
+        }
+        return FastMath.log(scale) * shape - FastMath.log(x) * (shape + 1) + FastMath.log(shape);
+    }
+
     /**
      * {@inheritDoc}
      * <p>

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PascalDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PascalDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PascalDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PascalDistribution.java Sun Oct 20 20:42:41 2013
@@ -68,6 +68,12 @@ public class PascalDistribution extends 
     private final int numberOfSuccesses;
     /** The probability of success. */
     private final double probabilityOfSuccess;
+    /** The value of {@code log(p)}, where {@code p} is the probability of success,
+     * stored for faster computation. */
+    private final double logProbabilityOfSuccess;
+    /** The value of {@code log(1-p)}, where {@code p} is the probability of success,
+     * stored for faster computation. */
+    private final double log1mProbabilityOfSuccess;
 
     /**
      * Create a Pascal distribution with the given number of successes and
@@ -112,6 +118,8 @@ public class PascalDistribution extends 
 
         numberOfSuccesses = r;
         probabilityOfSuccess = p;
+        logProbabilityOfSuccess = FastMath.log(p);
+        log1mProbabilityOfSuccess = FastMath.log1p(-p);
     }
 
     /**
@@ -147,6 +155,21 @@ public class PascalDistribution extends 
     }
 
     /** {@inheritDoc} */
+    @Override
+    public double logProbability(int x) {
+        double ret;
+        if (x < 0) {
+            ret = Double.NEGATIVE_INFINITY;
+        } else {
+            ret = CombinatoricsUtils.binomialCoefficientLog(x +
+                  numberOfSuccesses - 1, numberOfSuccesses - 1) +
+                  logProbabilityOfSuccess * numberOfSuccesses +
+                  log1mProbabilityOfSuccess * x;
+        }
+        return ret;
+    }
+
+    /** {@inheritDoc} */
     public double cumulativeProbability(int x) {
         double ret;
         if (x < 0) {

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PoissonDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PoissonDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PoissonDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/PoissonDistribution.java Sun Oct 20 20:42:41 2013
@@ -175,6 +175,22 @@ public class PoissonDistribution extends
     }
 
     /** {@inheritDoc} */
+    @Override
+    public double logProbability(int x) {
+        double ret;
+        if (x < 0 || x == Integer.MAX_VALUE) {
+            ret = Double.NEGATIVE_INFINITY;
+        } else if (x == 0) {
+            ret = -mean;
+        } else {
+            ret = -SaddlePointExpansion.getStirlingError(x) -
+                  SaddlePointExpansion.getDeviancePart(x, mean) -
+                  0.5 * FastMath.log(MathUtils.TWO_PI) - 0.5 * FastMath.log(x);
+        }
+        return ret;
+    }
+
+    /** {@inheritDoc} */
     public double cumulativeProbability(int x) {
         if (x < 0) {
             return 0;

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/TDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/TDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/TDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/TDistribution.java Sun Oct 20 20:42:41 2013
@@ -130,6 +130,18 @@ public class TDistribution extends Abstr
     }
 
     /** {@inheritDoc} */
+    @Override
+    public double logDensity(double x) {
+        final double n = degreesOfFreedom;
+        final double nPlus1Over2 = (n + 1) / 2;
+        return Gamma.logGamma(nPlus1Over2) -
+               0.5 * (FastMath.log(FastMath.PI) +
+                      FastMath.log(n)) -
+               Gamma.logGamma(n / 2) -
+               nPlus1Over2 * FastMath.log(1 + x * x / n);
+    }
+
+    /** {@inheritDoc} */
     public double cumulativeProbability(double x) {
         double ret;
         if (x == 0) {

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/WeibullDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/WeibullDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/WeibullDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/WeibullDistribution.java Sun Oct 20 20:42:41 2013
@@ -175,6 +175,26 @@ public class WeibullDistribution extends
     }
 
     /** {@inheritDoc} */
+    @Override
+    public double logDensity(double x) {
+        if (x < 0) {
+            return Double.NEGATIVE_INFINITY;
+        }
+
+        final double xscale = x / scale;
+        final double logxscalepow = FastMath.log(xscale) * (shape - 1);
+
+        /*
+         * FastMath.pow(x / scale, shape) =
+         * FastMath.pow(xscale, shape) =
+         * FastMath.pow(xscale, shape - 1) * xscale
+         */
+        final double xscalepowshape = FastMath.exp(logxscalepow) * xscale;
+
+        return FastMath.log(shape / scale) + logxscalepow - xscalepowshape;
+    }
+
+    /** {@inheritDoc} */
     public double cumulativeProbability(double x) {
         double ret;
         if (x <= 0.0) {

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ZipfDistribution.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ZipfDistribution.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ZipfDistribution.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/distribution/ZipfDistribution.java Sun Oct 20 20:42:41 2013
@@ -115,6 +115,16 @@ public class ZipfDistribution extends Ab
     }
 
     /** {@inheritDoc} */
+    @Override
+    public double logProbability(int x) {
+        if (x <= 0 || x > numberOfElements) {
+            return Double.NEGATIVE_INFINITY;
+        }
+
+        return -FastMath.log(x) * exponent - FastMath.log(generalizedHarmonic(numberOfElements, exponent));
+    }
+
+    /** {@inheritDoc} */
     public double cumulativeProbability(final int x) {
         if (x <= 0) {
             return 0.0;

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/IntegerDistributionAbstractTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/IntegerDistributionAbstractTest.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/IntegerDistributionAbstractTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/IntegerDistributionAbstractTest.java Sun Oct 20 20:42:41 2013
@@ -18,6 +18,7 @@ package org.apache.commons.math3.distrib
 
 import org.apache.commons.math3.TestUtils;
 import org.apache.commons.math3.exception.MathIllegalArgumentException;
+import org.apache.commons.math3.util.FastMath;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -60,6 +61,9 @@ public abstract class IntegerDistributio
     /** Values used to test probability density calculations */
     private double[] densityTestValues;
 
+    /** Values used to test logarithmic probability density calculations */
+    private double[] logDensityTestValues;
+
     /** Arguments used to test cumulative probability density calculations */
     private int[] cumulativeTestPoints;
 
@@ -83,6 +87,22 @@ public abstract class IntegerDistributio
     /** Creates the default probability density test expected values */
     public abstract double[] makeDensityTestValues();
 
+    /** Creates the default logarithmic probability density test expected values.
+     *
+     * The default implementation simply computes the logarithm of all the values in
+     * {@link #makeDensityTestValues()}.
+     *
+     * @return double[] the default logarithmic probability density test expected values.
+     */
+    public double[] makeLogDensityTestValues() {
+        final double[] densityTestValues = makeDensityTestValues();
+        final double[] logDensityTestValues = new double[densityTestValues.length];
+        for (int i = 0; i < densityTestValues.length; i++) {
+            logDensityTestValues[i] = FastMath.log(densityTestValues[i]);
+        }
+        return logDensityTestValues;
+    }
+
     /** Creates the default cumulative probability density test input values */
     public abstract int[] makeCumulativeTestPoints();
 
@@ -105,6 +125,7 @@ public abstract class IntegerDistributio
         distribution = makeDistribution();
         densityTestPoints = makeDensityTestPoints();
         densityTestValues = makeDensityTestValues();
+        logDensityTestValues = makeLogDensityTestValues();
         cumulativeTestPoints = makeCumulativeTestPoints();
         cumulativeTestValues = makeCumulativeTestValues();
         inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
@@ -119,6 +140,7 @@ public abstract class IntegerDistributio
         distribution = null;
         densityTestPoints = null;
         densityTestValues = null;
+        logDensityTestValues = null;
         cumulativeTestPoints = null;
         cumulativeTestValues = null;
         inverseCumulativeTestPoints = null;
@@ -140,6 +162,19 @@ public abstract class IntegerDistributio
     }
 
     /**
+     * Verifies that logarithmic probability density calculations match expected values
+     * using current test instance data.
+     */
+    protected void verifyLogDensities() {
+        for (int i = 0; i < densityTestPoints.length; i++) {
+            // FIXME: when logProbability methods are added to IntegerDistribution in 4.0, remove cast below
+            Assert.assertEquals("Incorrect log density value returned for " + densityTestPoints[i],
+                    logDensityTestValues[i],
+                    ((AbstractIntegerDistribution) distribution).logProbability(densityTestPoints[i]), tolerance);
+        }
+    }
+
+    /**
      * Verifies that cumulative probability density calculations match expected values
      * using current test instance data
      */
@@ -176,6 +211,15 @@ public abstract class IntegerDistributio
     }
 
     /**
+     * Verifies that logarithmic probability density calculations match expected values
+     * using default test instance data
+     */
+    @Test
+    public void testLogDensities() {
+        verifyLogDensities();
+    }
+
+    /**
      * Verifies that cumulative probability density calculations match expected values
      * using default test instance data
      */

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/LevyDistributionTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/LevyDistributionTest.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/LevyDistributionTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/LevyDistributionTest.java Sun Oct 20 20:42:41 2013
@@ -68,4 +68,15 @@ public class LevyDistributionTest extend
         };
     }
 
+    /** 
+     * Creates the default logarithmic probability density test expected values.
+     * Reference values are from R, version 2.14.1.
+     */
+    @Override
+    public double[] makeLogDensityTestValues() {
+        return new double[] {
+            -1987.561573341398d, -14.469328620160d, -3.843764717971d,
+            -0.883485488811d, 0.076793740349d, -1.127785768948d,
+            -2.650679030597d, -3.644945255983d};
+    }
 }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/PoissonDistributionTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/PoissonDistributionTest.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/PoissonDistributionTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/PoissonDistributionTest.java Sun Oct 20 20:42:41 2013
@@ -67,6 +67,18 @@ public class PoissonDistributionTest ext
                 0.156293451851d, 0.00529247667642d, 8.27746364655e-09};
     }
 
+    /** 
+     * Creates the default logarithmic probability density test expected values.
+     * Reference values are from R, version 2.14.1.
+     */
+    @Override
+    public double[] makeLogDensityTestValues() {
+        return new double[] { Double.NEGATIVE_INFINITY, -4.000000000000d,
+                -2.613705638880d, -1.920558458320d, -1.632876385868d,
+                -1.632876385868d, -1.856019937183d, -5.241468961877d,
+                -18.609729238356d};
+    }
+
     /**
      * Creates the default cumulative probability density test input values.
      */

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/RealDistributionAbstractTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/RealDistributionAbstractTest.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/RealDistributionAbstractTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/RealDistributionAbstractTest.java Sun Oct 20 20:42:41 2013
@@ -95,6 +95,9 @@ public abstract class RealDistributionAb
     /** Values used to test density calculations */
     private double[] densityTestValues;
 
+    /** Values used to test logarithmic density calculations */
+    private double[] logDensityTestValues;
+
     //-------------------- Abstract methods -----------------------------------
 
     /** Creates the default continuous distribution instance to use in tests. */
@@ -109,6 +112,18 @@ public abstract class RealDistributionAb
     /** Creates the default density test expected values */
     public abstract double[] makeDensityTestValues();
 
+    /** Creates the default logarithmic density test expected values.
+     * The default implementation simply computes the logarithm
+     * of each value returned by {@link #makeDensityTestValues()}.*/
+    public double[] makeLogDensityTestValues() {
+        final double[] densityTestValues = makeDensityTestValues();
+        final double[] logDensityTestValues = new double[densityTestValues.length];
+        for (int i = 0; i < densityTestValues.length; i++) {
+            logDensityTestValues[i] = FastMath.log(densityTestValues[i]);
+        }
+        return logDensityTestValues;
+    }
+
     //---- Default implementations of inverse test data generation methods ----
 
     /** Creates the default inverse cumulative probability test input values */
@@ -134,6 +149,7 @@ public abstract class RealDistributionAb
         inverseCumulativeTestPoints = makeInverseCumulativeTestPoints();
         inverseCumulativeTestValues = makeInverseCumulativeTestValues();
         densityTestValues = makeDensityTestValues();
+        logDensityTestValues = makeLogDensityTestValues();
     }
 
     /**
@@ -147,6 +163,7 @@ public abstract class RealDistributionAb
         inverseCumulativeTestPoints = null;
         inverseCumulativeTestValues = null;
         densityTestValues = null;
+        logDensityTestValues = null;
     }
 
     //-------------------- Verification methods -------------------------------
@@ -208,6 +225,19 @@ public abstract class RealDistributionAb
         }
     }
 
+    /**
+     * Verifies that logarithmic density calculations match expected values
+     */
+    protected void verifyLogDensities() {
+        // FIXME: when logProbability methods are added to RealDistribution in 4.0, remove cast below
+        for (int i = 0; i < cumulativeTestPoints.length; i++) {
+            TestUtils.assertEquals("Incorrect probability density value returned for "
+                    + cumulativeTestPoints[i], logDensityTestValues[i],
+                    ((AbstractRealDistribution) distribution).logDensity(cumulativeTestPoints[i]),
+                    getTolerance());
+        }
+    }
+
     //------------------------ Default test cases -----------------------------
 
     /**
@@ -238,6 +268,15 @@ public abstract class RealDistributionAb
     }
 
     /**
+     * Verifies that logarithmic density calculations return expected values
+     * for default test instance data
+     */
+    @Test
+    public void testLogDensities() {
+        verifyLogDensities();
+    }
+
+    /**
      * Verifies that probability computations are consistent
      */
     @Test

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/ZipfDistributionTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/ZipfDistributionTest.java?rev=1533974&r1=1533973&r2=1533974&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/ZipfDistributionTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/distribution/ZipfDistributionTest.java Sun Oct 20 20:42:41 2013
@@ -73,6 +73,17 @@ public class ZipfDistributionTest extend
             0.0569028586912, 0.0487738788782, 0.0426771440184, 0.0379352391275, 0.0341417152147, 0};
     }
 
+    /** 
+     * Creates the default logarithmic probability density test expected values.
+     * Reference values are from R, version 2.14.1.
+     */
+    @Override
+    public double[] makeLogDensityTestValues() {
+        return new double[] {Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY,
+        -1.0746d, -1.7678d, -2.1733d, -2.4609d, -2.6841d, -2.8664d, -3.0206d, -3.1541d,
+        -3.2719d, -3.3772d, Double.NEGATIVE_INFINITY};
+    }
+
     /** Creates the default cumulative probability density test input values */
     @Override
     public int[] makeCumulativeTestPoints() {