diff --git a/src/experimental/R/pascalTestCases b/src/experimental/R/pascalTestCases new file mode 100644 index 000000000..0a40ba1d8 --- /dev/null +++ b/src/experimental/R/pascalTestCases @@ -0,0 +1,127 @@ +# Copyright 2006 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#------------------------------------------------------------------------------ +# R source file to validate Pascal distribution tests in +# org.apache.commons.math.distribution.PascalDistributionTest +# +# To run the test, install R, put this file and testFunctions +# into the same directory, launch R from this directory and then enter +# source("") +# +# R functions used +# dnbinom(x, size, prob, mu, log = FALSE) <- density +# pnbinom(q, size, prob, mu, lower.tail = TRUE, log.p = FALSE) <- distribution +# qnbinom(p, size, prob, mu, lower.tail = TRUE, log.p = FALSE) <- quantiles +#------------------------------------------------------------------------------ +tol <- 1E-4 # error tolerance for tests +#------------------------------------------------------------------------------ +# Function definitions + +source("testFunctions") # utility test functions + +# function to verify density computations + +verifyDensity <- function(points, expected, size, p, tol) { + rDensityValues <- rep(0, length(points)) + i <- 0 + for (point in points) { + i <- i + 1 + rDensityValues[i] <- dnbinom(point, size, p) + } + output <- c("Density test size = ", size, ", p = ", p) + if (assertEquals(expected,rDensityValues,tol,"Density Values")) { + displayPadded(output, SUCCEEDED, WIDTH) + } else { + displayPadded(output, FAILED, WIDTH) + } +} + +# function to verify distribution computations + +verifyDistribution <- function(points, expected, size, p, tol) { + rDistValues <- rep(0, length(points)) + i <- 0 + for (point in points) { + i <- i + 1 + rDistValues[i] <- pnbinom(point, size, p) + } + output <- c("Distribution test size = ", size, ", p = ", p) + if (assertEquals(expected,rDistValues,tol,"Distribution Values")) { + displayPadded(output, SUCCEEDED, WIDTH) + } else { + displayPadded(output, FAILED, WIDTH) + } +} + +#-------------------------------------------------------------------------- +cat("Negative Binomial test cases\n") + +size <- 10.0 +probability <- 0.70 + +densityPoints <- c(-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) +densityValues <- c(0, 0.02824, 0.08474, 0.13982, + 0.16779, 0.16359, 0.1374, 0.10306, 0.070673, 0.04505, 0.02703, + 0.01540, 0.0084) +distributionValues <- c(0, 0.02824, 0.11299, 0.25281, 0.42060, 0.58420, + 0.72162, 0.82468, 0.89535, 0.94041, 0.967446, 0.98285, 0.99125) +inverseCumPoints <- c( 0, 0.001, 0.010, 0.025, 0.050, 0.100, 0.999, + 0.990, 0.975, 0.950, 0.900) +inverseCumValues <- c(-1, -1, -1, -1, 0, 0, 13, 10, 9, 8, 7) + +verifyDensity(densityPoints,densityValues,size,probability,tol) +verifyDistribution(densityPoints, distributionValues, size, probability, tol) + +i <- 0 +rInverseCumValues <- rep(0,length(inverseCumPoints)) +for (point in inverseCumPoints) { + i <- i + 1 + rInverseCumValues[i] <- qnbinom(point, size, probability) +} + +output <- c("Inverse Distribution test n = ", size, ", p = ", probability) +# R defines quantiles from the right, need to subtract one +if (assertEquals(inverseCumValues, rInverseCumValues-1, tol, + "Inverse Dist Values")) { + displayPadded(output, SUCCEEDED, 80) +} else { + displayPadded(output, FAILED, 80) +} + +# Degenerate cases + +size <- 5 +probability <- 0.0 + +densityPoints <- c(-1, 0, 1, 10, 11) +densityValues <- c(0, 0, 0, 0, 0) +distributionPoints <- c(-1, 0, 1, 5, 10) +distributionValues <- c(0, 0, 0, 0, 0) + +verifyDensity(densityPoints,densityValues,size,probability,tol) +verifyDistribution(distributionPoints,distributionValues,size,probability,tol) + +size <- 5 +probability <- 1.0 + +densityPoints <- c(-1, 0, 1, 2, 5, 10) +densityValues <- c(0, 1, 0, 0, 1, 0) +distributionPoints <- c(-1, 0, 1, 2, 5, 10) +distributionValues <- c(0, 1, 1, 1, 1, 1) + +verifyDensity(densityPoints,densityValues,size,probability,tol) +verifyDistribution(distributionPoints,distributionValues,size,probability,tol) + +displayDashes(WIDTH) diff --git a/src/java/org/apache/commons/math/distribution/DistributionFactory.java b/src/java/org/apache/commons/math/distribution/DistributionFactory.java index cef3b6da0..d1e48e001 100644 --- a/src/java/org/apache/commons/math/distribution/DistributionFactory.java +++ b/src/java/org/apache/commons/math/distribution/DistributionFactory.java @@ -33,6 +33,7 @@ import org.apache.commons.discovery.tools.DiscoverClass; *
  • Normal
  • *
  • Student's t
  • *
  • Weibull
  • + *
  • Pascal
  • * * * Common usage:
    @@ -80,6 +81,17 @@ public abstract class DistributionFactory {
         public abstract BinomialDistribution createBinomialDistribution(
             int numberOfTrials, double probabilityOfSuccess);
         
    +    /**
    +     * Create a Pascal distribution with the given number of successes and
    +     * probability of success.
    +     * 
    +     * @param numberOfSuccesses the number of successes.
    +     * @param probabilityOfSuccess the probability of success
    +     * @return a new Pascal distribution
    +     */
    +    public abstract PascalDistribution createPascalDistribution(
    +        int numberOfSuccesses, double probabilityOfSuccess);
    +    
         /**
          * Create a new cauchy distribution with the given median and scale.
          * @param median the median of the distribution
    diff --git a/src/java/org/apache/commons/math/distribution/DistributionFactoryImpl.java b/src/java/org/apache/commons/math/distribution/DistributionFactoryImpl.java
    index f72d7b8a9..986353d96 100644
    --- a/src/java/org/apache/commons/math/distribution/DistributionFactoryImpl.java
    +++ b/src/java/org/apache/commons/math/distribution/DistributionFactoryImpl.java
    @@ -154,4 +154,16 @@ public class DistributionFactoryImpl extends DistributionFactory {
             return new PoissonDistributionImpl(lambda);
         }
     
    +    /**
    +     * Create a Pascal distribution with the given number of successes and
    +     * probability of success.
    +     * 
    +     * @param numberOfSuccesses the number of successes.
    +     * @param probabilityOfSuccess the probability of success
    +     * @return a new Pascal distribution
    +     */
    +    public PascalDistribution createPascalDistribution(int numberOfSuccesses, double probabilityOfSuccess) {
    +        return new PascalDistributionImpl(numberOfSuccesses, probabilityOfSuccess);
    +    }
    +
     }
    diff --git a/src/java/org/apache/commons/math/distribution/PascalDistribution.java b/src/java/org/apache/commons/math/distribution/PascalDistribution.java
    new file mode 100644
    index 000000000..14b1e12fa
    --- /dev/null
    +++ b/src/java/org/apache/commons/math/distribution/PascalDistribution.java
    @@ -0,0 +1,62 @@
    +/*
    + * Copyright 2006 The Apache Software Foundation.
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *      http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package org.apache.commons.math.distribution;
    +
    +/**
    + * The Pascal Distribution.
    + *
    + * Instances of PascalDistribution objects should be created using
    + * {@link DistributionFactory#createPascalDistribution(int, double)}.
    + *
    + * 

    + * References: + *

    + *

    + * + * @version $Revision:$ + */ +public interface PascalDistribution extends IntegerDistribution { + /** + * Access the number of successes for this distribution. + * + * @return the number of successes + */ + int getNumberOfSuccesses(); + + /** + * Access the probability of success for this distribution. + * + * @return the probability of success + */ + double getProbabilityOfSuccess(); + + /** + * Change the number of successes for this distribution. + * + * @param successes the new number of successes + */ + void setNumberOfSuccesses(int successes); + + /** + * Change the probability of success for this distribution. + * + * @param p the new probability of success + */ + void setProbabilityOfSuccess(double p); +} \ No newline at end of file diff --git a/src/test/org/apache/commons/math/distribution/PascalDistributionTest.java b/src/test/org/apache/commons/math/distribution/PascalDistributionTest.java new file mode 100644 index 000000000..bc0bd3b92 --- /dev/null +++ b/src/test/org/apache/commons/math/distribution/PascalDistributionTest.java @@ -0,0 +1,104 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.math.distribution; + +/** + * Test cases for PascalDistribution. + * Extends IntegerDistributionAbstractTest. See class javadoc for + * IntegerDistributionAbstractTest for details. + * + * @version $Revision:$ $Date:$ + */ +public class PascalDistributionTest extends IntegerDistributionAbstractTest { + + /** + * Constructor for PascalDistributionTest. + * @param name + */ + public PascalDistributionTest(String name) { + super(name); + } + + //-------------- Implementations for abstract methods ----------------------- + + /** Creates the default discrete distribution instance to use in tests. */ + public IntegerDistribution makeDistribution() { + return DistributionFactory.newInstance().createPascalDistribution(10,0.70); + } + + /** Creates the default probability density test input values */ + public int[] makeDensityTestPoints() { + return new int[] {-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + } + + /** Creates the default probability density test expected values */ + public double[] makeDensityTestValues() { + return new double[] {0d, 0.02824d, 0.08474d, 0.13982d, + 0.16779d, 0.16359d, 0.1374d, 0.10306d, 0.070673d, 0.04505d, 0.02703d, 0.01540d, 0.0084}; + } + + /** Creates the default cumulative probability density test input values */ + public int[] makeCumulativeTestPoints() { + return makeDensityTestPoints(); + } + + /** Creates the default cumulative probability density test expected values */ + public double[] makeCumulativeTestValues() { + return new double[] {0d, 0.02824d, 0.11299d, 0.25281d, 0.42060d, 0.58420d, + 0.72162d, 0.82468d, 0.89535d, 0.94041d, 0.967446d, 0.98285, 0.99125d}; + } + + /** Creates the default inverse cumulative probability test input values */ + public double[] makeInverseCumulativeTestPoints() { + return new double[] {0, 0.001d, 0.010d, 0.025d, 0.050d, 0.100d, 0.999d, + 0.990d, 0.975d, 0.950d, 0.900d, 1}; + } + + /** Creates the default inverse cumulative probability density test expected values */ + public int[] makeInverseCumulativeTestValues() { + return new int[] {-1, -1, -1, -1, 0, 0, 13, 10, 9, 8, 7, Integer.MAX_VALUE}; + } + + //----------------- Additional test cases --------------------------------- + + /** Test degenerate case p = 0 */ + public void testDegenerate0() throws Exception { + setDistribution(DistributionFactory.newInstance().createPascalDistribution(5,0.0d)); + setCumulativeTestPoints(new int[] {-1, 0, 1, 5, 10 }); + setCumulativeTestValues(new double[] {0d, 0d, 0d, 0d, 0d}); + setDensityTestPoints(new int[] {-1, 0, 1, 10, 11}); + setDensityTestValues(new double[] {0d, 0d, 0d, 0d, 0d}); + setInverseCumulativeTestPoints(new double[] {0.1d, 0.5d}); + setInverseCumulativeTestValues(new int[] {Integer.MAX_VALUE - 1, Integer.MAX_VALUE - 1}); + verifyDensities(); + verifyCumulativeProbabilities(); + verifyInverseCumulativeProbabilities(); + } + + /** Test degenerate case p = 1 */ + public void testDegenerate1() throws Exception { + setDistribution(DistributionFactory.newInstance().createPascalDistribution(5,1.0d)); + setCumulativeTestPoints(new int[] {-1, 0, 1, 2, 5, 10 }); + setCumulativeTestValues(new double[] {0d, 1d, 1d, 1d, 1d, 1d}); + setDensityTestPoints(new int[] {-1, 0, 1, 2, 5, 10}); + setDensityTestValues(new double[] {0d, 1d, 0d, 0d, 0d, 0d}); + setInverseCumulativeTestPoints(new double[] {0.1d, 0.5d}); + setInverseCumulativeTestValues(new int[] {-1, -1}); + verifyDensities(); + verifyCumulativeProbabilities(); + verifyInverseCumulativeProbabilities(); + } +} diff --git a/xdocs/changes.xml b/xdocs/changes.xml index b59638409..5bc8e5bb3 100644 --- a/xdocs/changes.xml +++ b/xdocs/changes.xml @@ -43,6 +43,9 @@ Commons Math Release Notes Made ComplexFormat format double values with a provided NumberFormat instance instead of using the real part format for all values. + + Added Pascal distribution implementation. +