diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/math/statistics/distribution')
40 files changed, 1982 insertions, 357 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/AbstractDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/AbstractDistribution.java new file mode 100644 index 00000000..30481d00 --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/AbstractDistribution.java @@ -0,0 +1,115 @@ +package de.lmu.ifi.dbs.elki.math.statistics.distribution; + +/* + This file is part of ELKI: + Environment for Developing KDD-Applications Supported by Index-Structures + + Copyright (C) 2013 + Ludwig-Maximilians-Universität München + Lehr- und Forschungseinheit für Datenbanksysteme + ELKI Development Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import java.util.Random; + +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.RandomParameter; + +/** + * Abstract base class for distributions. + * + * @author Erich Schubert + */ +public abstract class AbstractDistribution implements Distribution { + /** + * Random source. + */ + final protected Random random; + + /** + * Constructor. + * + * @param rnd Random source + */ + public AbstractDistribution(RandomFactory rnd) { + super(); + this.random = rnd.getRandom(); + } + + /** + * Constructor. + * + * @param rnd Random source + */ + public AbstractDistribution(Random rnd) { + super(); + this.random = rnd; + } + + @Override + public double nextRandom() { + return quantile(random.nextDouble()); + } + + /** + * Parameterization class. + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public abstract static class Parameterizer extends AbstractParameterizer { + /** + * Parameter to specify the random seeding source. + */ + public static final OptionID RANDOM_ID = new OptionID("distribution.random", "Random generation data source."); + + /** + * Location parameter. + */ + public static final OptionID LOCATION_ID = new OptionID("distribution.location", "Distribution location parameter"); + + /** + * Scale parameter. + */ + public static final OptionID SCALE_ID = new OptionID("distribution.scale", "Distribution scale parameter"); + + /** + * Shape parameter. + */ + public static final OptionID SHAPE_ID = new OptionID("distribution.shape", "Distribution shape parameter"); + + /** + * Random source. + */ + RandomFactory rnd; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + RandomParameter randomP = new RandomParameter(RANDOM_ID); + if (config.grab(randomP)) { + rnd = randomP.getValue(); + } + } + + @Override + abstract protected Distribution makeInstance(); + } +} diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/BetaDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/BetaDistribution.java index c48583ea..04d55262 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/BetaDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/BetaDistribution.java @@ -2,7 +2,11 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random;
+import de.lmu.ifi.dbs.elki.utilities.RandomFactory;
import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
/*
This file is part of ELKI:
@@ -34,7 +38,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.AbortException; * @author Jan Brusis
* @author Erich Schubert
*/
-public class BetaDistribution implements Distribution {
+public class BetaDistribution extends AbstractDistribution {
/**
* Numerical precision to use
*/
@@ -66,11 +70,6 @@ public class BetaDistribution implements Distribution { private final double beta;
/**
- * For random number generation
- */
- private Random random;
-
- /**
* Log beta(a, b) cache
*/
private double logbab;
@@ -82,7 +81,7 @@ public class BetaDistribution implements Distribution { * @param b shape Parameter b
*/
public BetaDistribution(double a, double b) {
- this(a, b, new Random());
+ this(a, b, (Random) null);
}
/**
@@ -93,7 +92,25 @@ public class BetaDistribution implements Distribution { * @param random Random generator
*/
public BetaDistribution(double a, double b, Random random) {
- super();
+ super(random);
+ if (a <= 0.0 || b <= 0.0) {
+ throw new IllegalArgumentException("Invalid parameters for Beta distribution.");
+ }
+
+ this.alpha = a;
+ this.beta = b;
+ this.logbab = logBeta(a, b);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param a shape Parameter a
+ * @param b shape Parameter b
+ * @param random Random generator
+ */
+ public BetaDistribution(double a, double b, RandomFactory random) {
+ super(random);
if (a <= 0.0 || b <= 0.0) {
throw new IllegalArgumentException("Invalid parameters for Beta distribution.");
}
@@ -101,7 +118,6 @@ public class BetaDistribution implements Distribution { this.alpha = a;
this.beta = b;
this.logbab = logBeta(a, b);
- this.random = random;
}
@Override
@@ -457,7 +473,8 @@ public class BetaDistribution implements Distribution { } else {
double r = beta + beta;
double t = 1. / (9. * beta);
- t = r * Math.pow(1. - t + y * Math.sqrt(t), 3.0);
+ final double a = 1. - t + y * Math.sqrt(t);
+ t = r * a * a * a;
if (t <= 0.) {
x = 1. - Math.exp((Math.log1p(-p) + Math.log(beta) + logbeta) / beta);
} else {
@@ -525,4 +542,46 @@ public class BetaDistribution implements Distribution { // Not converged in Newton-Raphson
throw new AbortException("Beta quantile computation did not converge.");
}
+
+ /**
+ * Parameterization class
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer extends AbstractDistribution.Parameterizer {
+ /**
+ * Alpha parameter.
+ */
+ public static final OptionID ALPHA_ID = new OptionID("distribution.beta.alpha", "Beta distribution alpha parameter");
+
+ /**
+ * Beta parameter.
+ */
+ public static final OptionID BETA_ID = new OptionID("distribution.beta.beta", "Beta distribution beta parameter");
+
+ /** Parameters. */
+ double alpha, beta;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+
+ DoubleParameter alphaP = new DoubleParameter(ALPHA_ID);
+ if (config.grab(alphaP)) {
+ alpha = alphaP.doubleValue();
+ }
+
+ DoubleParameter betaP = new DoubleParameter(BETA_ID);
+ if (config.grab(betaP)) {
+ beta = betaP.doubleValue();
+ }
+ }
+
+ @Override
+ protected BetaDistribution makeInstance() {
+ return new BetaDistribution(alpha, beta, rnd);
+ }
+ }
}
diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/CauchyDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/CauchyDistribution.java index c218a37f..2b5d4949 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/CauchyDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/CauchyDistribution.java @@ -25,12 +25,17 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Cauchy distribution. * * @author Erich Schubert */ -public class CauchyDistribution implements Distribution { +public class CauchyDistribution extends AbstractDistribution { /** * The location (x0) parameter. */ @@ -42,18 +47,13 @@ public class CauchyDistribution implements Distribution { final double shape; /** - * The random generator. - */ - private Random random; - - /** * Constructor with default random. * * @param location Location (x0) * @param shape Shape (gamma) */ public CauchyDistribution(double location, double shape) { - this(location, shape, new Random()); + this(location, shape, (Random) null); } /** @@ -64,10 +64,22 @@ public class CauchyDistribution implements Distribution { * @param random Random generator */ public CauchyDistribution(double location, double shape, Random random) { - super(); + super(random); + this.location = location; + this.shape = shape; + } + + /** + * Constructor. + * + * @param location Location (x0) + * @param shape Shape (gamma) + * @param random Random generator + */ + public CauchyDistribution(double location, double shape, RandomFactory random) { + super(random); this.location = location; this.shape = shape; - this.random = random; } @Override @@ -132,4 +144,41 @@ public class CauchyDistribution implements Distribution { public String toString() { return "CauchyDistribution(location=" + location + ", shape=" + shape + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Shape parameter gamma. + */ + public static final OptionID SHAPE_ID = new OptionID("distribution.cauchy.shape", "Cauchy distribution gamma/shape parameter."); + + /** Parameters. */ + double location, shape; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locP = new DoubleParameter(LOCATION_ID); + if (config.grab(locP)) { + location = locP.doubleValue(); + } + + DoubleParameter shapeP = new DoubleParameter(SHAPE_ID); + if (config.grab(shapeP)) { + shape = shapeP.doubleValue(); + } + } + + @Override + protected CauchyDistribution makeInstance() { + return new CauchyDistribution(location, shape, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiDistribution.java index a552e413..5f144946 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiDistribution.java @@ -1,8 +1,5 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; -import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages; -import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; - /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures @@ -26,6 +23,14 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import java.util.Random; + +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages; +import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Chi distribution. * @@ -33,7 +38,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; * * @apiviz.composedOf ChiSquaredDistribution */ -public class ChiDistribution implements Distribution { +public class ChiDistribution extends AbstractDistribution { /** * Degrees of freedom. Usually integer. */ @@ -50,9 +55,31 @@ public class ChiDistribution implements Distribution { * @param dof Degrees of freedom. Usually integer. */ public ChiDistribution(double dof) { - super(); + this(dof, (Random) null); + } + + /** + * Constructor. + * + * @param dof Degrees of freedom. Usually integer. + * @param random Random number generator. + */ + public ChiDistribution(double dof, Random random) { + super(random); this.dof = dof; - this.chisq = new ChiSquaredDistribution(dof); + this.chisq = new ChiSquaredDistribution(dof, random); + } + + /** + * Constructor. + * + * @param dof Degrees of freedom. Usually integer. + * @param random Random number generator. + */ + public ChiDistribution(double dof, RandomFactory random) { + super(random); + this.dof = dof; + this.chisq = new ChiSquaredDistribution(dof, random); } @Override @@ -73,7 +100,7 @@ public class ChiDistribution implements Distribution { * @return Pdf value */ public static double pdf(double val, double dof) { - if(val < 0) { + if (val < 0) { return 0.0; } return Math.sqrt(ChiSquaredDistribution.pdf(val, dof)); @@ -105,4 +132,31 @@ public class ChiDistribution implements Distribution { public String toString() { return "ChiDistribution(dof=" + dof + ")"; } -}
\ No newline at end of file + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double dof; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter dofP = new DoubleParameter(ChiSquaredDistribution.Parameterizer.DOF_ID); + if (config.grab(dofP)) { + dof = dofP.doubleValue(); + } + } + + @Override + protected ChiDistribution makeInstance() { + return new ChiDistribution(dof, rnd); + } + } +} diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiSquaredDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiSquaredDistribution.java index 235367cd..6fd432b2 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiSquaredDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ChiSquaredDistribution.java @@ -1,7 +1,5 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; -import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; - /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures @@ -24,6 +22,13 @@ import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import java.util.Random; + +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Chi-Squared distribution (a specialization of the Gamma distribution). @@ -37,7 +42,27 @@ public class ChiSquaredDistribution extends GammaDistribution { * @param dof Degrees of freedom. */ public ChiSquaredDistribution(double dof) { - super(.5 * dof, .5); + this(dof, (Random) null); + } + + /** + * Constructor. + * + * @param dof Degrees of freedom. + * @param random Random generator. + */ + public ChiSquaredDistribution(double dof, Random random) { + super(.5 * dof, .5, random); + } + + /** + * Constructor. + * + * @param dof Degrees of freedom. + * @param random Random generator. + */ + public ChiSquaredDistribution(double dof, RandomFactory random) { + super(.5 * dof, .5, random); } /** @@ -95,4 +120,36 @@ public class ChiSquaredDistribution extends GammaDistribution { public String toString() { return "ChiSquaredDistribution(dof=" + (2 * getK()) + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Degrees of freedom parameter. + */ + public static final OptionID DOF_ID = new OptionID("distribution.chi.dof", "Chi distribution degrees of freedom parameter."); + + /** Parameters. */ + double dof; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter dofP = new DoubleParameter(DOF_ID); + if (config.grab(dofP)) { + dof = dofP.doubleValue(); + } + } + + @Override + protected ChiSquaredDistribution makeInstance() { + return new ChiSquaredDistribution(dof, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ConstantDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ConstantDistribution.java index 35d5294f..b31eaa3d 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ConstantDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ConstantDistribution.java @@ -1,5 +1,10 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures @@ -56,11 +61,43 @@ public class ConstantDistribution implements Distribution { @Override public double cdf(double val) { - return (val >= c) ? 1.0 : 0.0; + return (c < val) ? 0. : (c > val) ? 1. : .5; } @Override public double quantile(double val) { return c; } -}
\ No newline at end of file + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractParameterizer { + /** + * Constant value parameter + */ + public static final OptionID CONSTANT_ID = new OptionID("distribution.constant", "Constant value."); + + /** Parameters. */ + double constant; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter constP = new DoubleParameter(CONSTANT_ID); + if (config.grab(constP)) { + constant = constP.doubleValue(); + } + } + + @Override + protected ConstantDistribution makeInstance() { + return new ConstantDistribution(constant); + } + } +} diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/Distribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/Distribution.java index 519ba0b3..0c60e02f 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/Distribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/Distribution.java @@ -23,12 +23,14 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import de.lmu.ifi.dbs.elki.utilities.optionhandling.Parameterizable; + /** * Statistical distributions, with their common functions. * * @author Erich Schubert */ -public interface Distribution { +public interface Distribution extends Parameterizable { /** * Return the density of an existing value * diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentialDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentialDistribution.java index e5af3e5b..33d8e853 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentialDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentialDistribution.java @@ -25,17 +25,17 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Exponential distribution. * * @author Erich Schubert */ -public class ExponentialDistribution implements Distribution { - /** - * Random generator. - */ - Random rnd; - +public class ExponentialDistribution extends AbstractDistribution { /** * Rate, inverse of mean */ @@ -52,7 +52,7 @@ public class ExponentialDistribution implements Distribution { * @param rate Rate parameter (1/scale) */ public ExponentialDistribution(double rate) { - this(rate, 0.0, null); + this(rate, 0.0, (Random) null); } /** @@ -62,7 +62,7 @@ public class ExponentialDistribution implements Distribution { * @param location Location parameter */ public ExponentialDistribution(double rate, double location) { - this(rate, location, null); + this(rate, location, (Random) null); } /** @@ -83,10 +83,22 @@ public class ExponentialDistribution implements Distribution { * @param random Random generator */ public ExponentialDistribution(double rate, double location, Random random) { - super(); + super(random); + this.rate = rate; + this.location = location; + } + + /** + * Constructor. + * + * @param rate Rate parameter (1/scale) + * @param location Location parameter + * @param random Random generator + */ + public ExponentialDistribution(double rate, double location, RandomFactory random) { + super(random); this.rate = rate; this.location = location; - this.rnd = random; } @Override @@ -160,11 +172,48 @@ public class ExponentialDistribution implements Distribution { */ @Override public double nextRandom() { - return -Math.log(rnd.nextDouble()) / rate + location; + return -Math.log(random.nextDouble()) / rate + location; } @Override public String toString() { return "ExponentialDistribution(rate=" + rate + ", location=" + location + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Shape parameter gamma. + */ + public static final OptionID RATE_ID = new OptionID("distribution.exponential.rate", "Exponential distribution rate (lambda) parameter (inverse of scale)."); + + /** Parameters. */ + double location, rate; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locP = new DoubleParameter(LOCATION_ID); + if (config.grab(locP)) { + location = locP.doubleValue(); + } + + DoubleParameter rateP = new DoubleParameter(RATE_ID); + if (config.grab(rateP)) { + rate = rateP.doubleValue(); + } + } + + @Override + protected ExponentialDistribution makeInstance() { + return new ExponentialDistribution(rate, location, rnd); + } + } }
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentiallyModifiedGaussianDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentiallyModifiedGaussianDistribution.java index 01e91777..22e75e3d 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentiallyModifiedGaussianDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/ExponentiallyModifiedGaussianDistribution.java @@ -25,9 +25,13 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.math.MathUtil; import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages; import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Exponentially modified Gaussian (EMG) distribution (ExGaussian distribution) @@ -36,7 +40,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; * @author Erich Schubert */ @Alias({ "exgaussian" }) -public class ExponentiallyModifiedGaussianDistribution implements Distribution { +public class ExponentiallyModifiedGaussianDistribution extends AbstractDistribution { /** * Mean value for the generator */ @@ -53,9 +57,19 @@ public class ExponentiallyModifiedGaussianDistribution implements Distribution { private double lambda; /** - * Random generator. + * Constructor for ExGaussian distribution + * + * @param mean Mean + * @param stddev Standard Deviation + * @param lambda Rate + * @param random Random */ - private Random rnd; + public ExponentiallyModifiedGaussianDistribution(double mean, double stddev, double lambda, Random random) { + super(random); + this.mean = mean; + this.stddev = stddev; + this.lambda = lambda; + } /** * Constructor for ExGaussian distribution @@ -63,14 +77,13 @@ public class ExponentiallyModifiedGaussianDistribution implements Distribution { * @param mean Mean * @param stddev Standard Deviation * @param lambda Rate - * @param rnd Random + * @param random Random */ - public ExponentiallyModifiedGaussianDistribution(double mean, double stddev, double lambda, Random rnd) { - super(); + public ExponentiallyModifiedGaussianDistribution(double mean, double stddev, double lambda, RandomFactory random) { + super(random); this.mean = mean; this.stddev = stddev; this.lambda = lambda; - this.rnd = rnd; } /** @@ -81,7 +94,7 @@ public class ExponentiallyModifiedGaussianDistribution implements Distribution { * @param lambda Rate */ public ExponentiallyModifiedGaussianDistribution(double mean, double stddev, double lambda) { - this(mean, stddev, lambda, null); + this(mean, stddev, lambda, (Random) null); } @Override @@ -105,8 +118,8 @@ public class ExponentiallyModifiedGaussianDistribution implements Distribution { @Override public double nextRandom() { - double no = mean + rnd.nextGaussian() * stddev; - double ex = -Math.log(rnd.nextDouble()) / lambda; + double no = mean + random.nextGaussian() * stddev; + double ex = -Math.log(random.nextDouble()) / lambda; return no + ex; } @@ -147,8 +160,9 @@ public class ExponentiallyModifiedGaussianDistribution implements Distribution { */ public static double pdf(double x, double mu, double sigma, double lambda) { final double dx = x - mu; - final double erfc = NormalDistribution.erfc(lambda * sigma * sigma - dx); - return .5 * lambda * Math.exp(lambda * (lambda * sigma * sigma * .5 - dx)) * erfc; + final double lss = lambda * sigma * sigma; + final double erfc = NormalDistribution.erfc((lss - dx) / (sigma * MathUtil.SQRT2)); + return .5 * lambda * Math.exp(lambda * (lss * .5 - dx)) * erfc; } /** @@ -185,4 +199,41 @@ public class ExponentiallyModifiedGaussianDistribution implements Distribution { // FIXME: implement! throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET); } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double mean, stddev, lambda; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locP = new DoubleParameter(LOCATION_ID); + if(config.grab(locP)) { + mean = locP.doubleValue(); + } + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if(config.grab(scaleP)) { + stddev = scaleP.doubleValue(); + } + + DoubleParameter rateP = new DoubleParameter(ExponentialDistribution.Parameterizer.RATE_ID); + if(config.grab(rateP)) { + lambda = rateP.doubleValue(); + } + } + + @Override + protected ExponentiallyModifiedGaussianDistribution makeInstance() { + return new ExponentiallyModifiedGaussianDistribution(mean, stddev, lambda, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GammaDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GammaDistribution.java index 1b9e2b42..850b0e3a 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GammaDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GammaDistribution.java @@ -27,14 +27,18 @@ import java.util.Random; import de.lmu.ifi.dbs.elki.logging.LoggingUtil; import de.lmu.ifi.dbs.elki.math.MathUtil; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Gamma Distribution, with random generation and density functions. * * @author Erich Schubert */ -public class GammaDistribution implements Distribution { +public class GammaDistribution extends AbstractDistribution { /** * Euler–Mascheroni constant */ @@ -77,9 +81,21 @@ public class GammaDistribution implements Distribution { private final double theta; /** - * The random generator. + * Constructor for Gamma distribution. + * + * @param k k, alpha aka. "shape" parameter + * @param theta Theta = 1.0/Beta aka. "scaling" parameter + * @param random Random generator */ - private Random random; + public GammaDistribution(double k, double theta, Random random) { + super(random); + if (!(k > 0.0) || !(theta > 0.0)) { // Note: also tests for NaNs! + throw new IllegalArgumentException("Invalid parameters for Gamma distribution: " + k + " " + theta); + } + + this.k = k; + this.theta = theta; + } /** * Constructor for Gamma distribution. @@ -88,15 +104,14 @@ public class GammaDistribution implements Distribution { * @param theta Theta = 1.0/Beta aka. "scaling" parameter * @param random Random generator */ - public GammaDistribution(double k, double theta, Random random) { - super(); + public GammaDistribution(double k, double theta, RandomFactory random) { + super(random); if (!(k > 0.0) || !(theta > 0.0)) { // Note: also tests for NaNs! throw new IllegalArgumentException("Invalid parameters for Gamma distribution: " + k + " " + theta); } this.k = k; this.theta = theta; - this.random = random; } /** @@ -106,7 +121,7 @@ public class GammaDistribution implements Distribution { * @param theta Theta = 1.0/Beta aka. "scaling" parameter */ public GammaDistribution(double k, double theta) { - this(k, theta, new Random()); + this(k, theta, (Random) null); } @Override @@ -631,12 +646,13 @@ public class GammaDistribution implements Distribution { // (Math.log(alpha) + g); // return Math.exp((lgam1pa + logp) / alpha + MathUtil.LOG2); // This is literal AS 91, above is the GNU R variant. - return Math.pow(p * k * Math.exp(g + k * MathUtil.LOG2), 1 / k); + return Math.pow(p * k * Math.exp(g + k * MathUtil.LOG2), 1. / k); } else if (nu > 0.32) { // Wilson and Hilferty estimate: - AS 91 at 3 final double x = NormalDistribution.quantile(p, 0, 1); final double p1 = 2. / (9. * nu); - double ch = nu * Math.pow(x * Math.sqrt(p1) + 1 - p1, 3); + final double a = x * Math.sqrt(p1) + 1 - p1; + double ch = nu * a * a * a; // Better approximation for p tending to 1: if (ch > 2.2 * nu + 6) { @@ -890,4 +906,48 @@ public class GammaDistribution implements Distribution { return trigamma(x + 1.) - 1. / (x * x); } } + + /** + * Parameterization class + * + * TODO: allow alternate parameterization, with alpha+beta? + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * K parameter. + */ + public static final OptionID K_ID = new OptionID("distribution.gamma.k", "Gamma distribution k = alpha parameter."); + + /** + * Theta parameter. + */ + public static final OptionID THETA_ID = new OptionID("distribution.gamma.theta", "Gamma distribution theta = 1/beta parameter."); + + /** Parameters. */ + double k, theta; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter kP = new DoubleParameter(K_ID); + if (config.grab(kP)) { + k = kP.doubleValue(); + } + + DoubleParameter thetaP = new DoubleParameter(THETA_ID); + if (config.grab(thetaP)) { + theta = thetaP.doubleValue(); + } + } + + @Override + protected GammaDistribution makeInstance() { + return new GammaDistribution(k, theta, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedExtremeValueDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedExtremeValueDistribution.java index 9cd6cb4e..0d3fd4f8 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedExtremeValueDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedExtremeValueDistribution.java @@ -1,7 +1,5 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; -import java.util.Random; - /* This file is part of ELKI: Environment for Developing KDD-Applications Supported by Index-Structures @@ -25,6 +23,12 @@ import java.util.Random; along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import java.util.Random; + +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Generalized Extreme Value (GEV) distribution, also known as Fisher–Tippett * distribution. @@ -37,16 +41,22 @@ import java.util.Random; * * @author Erich Schubert */ -public class GeneralizedExtremeValueDistribution implements Distribution { +public class GeneralizedExtremeValueDistribution extends AbstractDistribution { /** * Parameters (location, scale, shape) */ final double mu, sigma, k; /** - * Random number generator. + * Constructor. + * + * @param mu Location parameter mu + * @param sigma Scale parameter sigma + * @param k Shape parameter k */ - Random random; + public GeneralizedExtremeValueDistribution(double mu, double sigma, double k) { + this(mu, sigma, k, (Random) null); + } /** * Constructor. @@ -54,9 +64,13 @@ public class GeneralizedExtremeValueDistribution implements Distribution { * @param mu Location parameter mu * @param sigma Scale parameter sigma * @param k Shape parameter k + * @param random Random number generator */ - public GeneralizedExtremeValueDistribution(double mu, double sigma, double k) { - this(mu, sigma, k, null); + public GeneralizedExtremeValueDistribution(double mu, double sigma, double k, RandomFactory random) { + super(random); + this.mu = mu; + this.sigma = sigma; + this.k = k; } /** @@ -68,11 +82,10 @@ public class GeneralizedExtremeValueDistribution implements Distribution { * @param random Random number generator */ public GeneralizedExtremeValueDistribution(double mu, double sigma, double k, Random random) { - super(); + super(random); this.mu = mu; this.sigma = sigma; this.k = k; - this.random = random; } /** @@ -156,12 +169,44 @@ public class GeneralizedExtremeValueDistribution implements Distribution { } @Override - public double nextRandom() { - return quantile(random.nextDouble()); - } - - @Override public String toString() { return "GeneralizedExtremeValueDistribution(sigma=" + sigma + ", mu=" + mu + ", k=" + k + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double mu, sigma, k; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter muP = new DoubleParameter(LOCATION_ID); + if (config.grab(muP)) { + mu = muP.doubleValue(); + } + + DoubleParameter sigmaP = new DoubleParameter(SCALE_ID); + if (config.grab(sigmaP)) { + sigma = sigmaP.doubleValue(); + } + + DoubleParameter kP = new DoubleParameter(SHAPE_ID); + if (config.grab(kP)) { + k = kP.doubleValue(); + } + } + + @Override + protected GeneralizedExtremeValueDistribution makeInstance() { + return new GeneralizedExtremeValueDistribution(mu, sigma, k, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticAlternateDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticAlternateDistribution.java index 467d6aae..eb5e1b1a 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticAlternateDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticAlternateDistribution.java @@ -24,6 +24,10 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; */ import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Generalized logistic distribution. * @@ -33,7 +37,7 @@ import java.util.Random; * * @author Erich Schubert */ -public class GeneralizedLogisticAlternateDistribution implements Distribution { +public class GeneralizedLogisticAlternateDistribution extends AbstractDistribution { /** * Parameters: location and scale */ @@ -45,9 +49,15 @@ public class GeneralizedLogisticAlternateDistribution implements Distribution { double shape; /** - * Random number generator + * Constructor. + * + * @param location Location + * @param scale Scale + * @param shape Shape parameter */ - Random random; + public GeneralizedLogisticAlternateDistribution(double location, double scale, double shape) { + this(location, scale, shape, (Random) null); + } /** * Constructor. @@ -55,9 +65,16 @@ public class GeneralizedLogisticAlternateDistribution implements Distribution { * @param location Location * @param scale Scale * @param shape Shape parameter + * @param random Random number generator */ - public GeneralizedLogisticAlternateDistribution(double location, double scale, double shape) { - this(location, scale, shape, null); + public GeneralizedLogisticAlternateDistribution(double location, double scale, double shape, Random random) { + super(random); + this.location = location; + this.scale = scale; + this.shape = shape; + if (!(shape > -1.) || !(shape < 1.)) { + throw new ArithmeticException("Invalid shape parameter - must be -1 to +1, is: " + shape); + } } /** @@ -68,12 +85,11 @@ public class GeneralizedLogisticAlternateDistribution implements Distribution { * @param shape Shape parameter * @param random Random number generator */ - public GeneralizedLogisticAlternateDistribution(double location, double scale, double shape, Random random) { - super(); + public GeneralizedLogisticAlternateDistribution(double location, double scale, double shape, RandomFactory random) { + super(random); this.location = location; this.scale = scale; this.shape = shape; - this.random = random; if (!(shape > -1.) || !(shape < 1.)) { throw new ArithmeticException("Invalid shape parameter - must be -1 to +1, is: " + shape); } @@ -159,4 +175,41 @@ public class GeneralizedLogisticAlternateDistribution implements Distribution { public String toString() { return "GeneralizedLogisticAlternateDistribution(location=" + location + ", scale=" + scale + ", shape=" + shape + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double location, scale, shape; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locationP = new DoubleParameter(LOCATION_ID); + if (config.grab(locationP)) { + location = locationP.doubleValue(); + } + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if (config.grab(scaleP)) { + scale = scaleP.doubleValue(); + } + + DoubleParameter shapeP = new DoubleParameter(SHAPE_ID); + if (config.grab(shapeP)) { + shape = shapeP.doubleValue(); + } + } + + @Override + protected GeneralizedLogisticAlternateDistribution makeInstance() { + return new GeneralizedLogisticAlternateDistribution(location, scale, shape, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticDistribution.java index 76f71107..467ad4f9 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GeneralizedLogisticDistribution.java @@ -24,6 +24,10 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; */ import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Generalized logistic distribution. (Type I, Skew-logistic distribution) * @@ -37,7 +41,7 @@ import java.util.Random; * * @author Erich Schubert */ -public class GeneralizedLogisticDistribution implements Distribution { +public class GeneralizedLogisticDistribution extends AbstractDistribution { /** * Parameters: location and scale */ @@ -49,9 +53,15 @@ public class GeneralizedLogisticDistribution implements Distribution { double shape; /** - * Random number generator + * Constructor. + * + * @param location Location + * @param scale Scale + * @param shape Shape parameter */ - Random random; + public GeneralizedLogisticDistribution(double location, double scale, double shape) { + this(location, scale, shape, (Random) null); + } /** * Constructor. @@ -59,9 +69,13 @@ public class GeneralizedLogisticDistribution implements Distribution { * @param location Location * @param scale Scale * @param shape Shape parameter + * @param random Random number generator */ - public GeneralizedLogisticDistribution(double location, double scale, double shape) { - this(location, scale, shape, null); + public GeneralizedLogisticDistribution(double location, double scale, double shape, Random random) { + super(random); + this.location = location; + this.scale = scale; + this.shape = shape; } /** @@ -72,12 +86,11 @@ public class GeneralizedLogisticDistribution implements Distribution { * @param shape Shape parameter * @param random Random number generator */ - public GeneralizedLogisticDistribution(double location, double scale, double shape, Random random) { - super(); + public GeneralizedLogisticDistribution(double location, double scale, double shape, RandomFactory random) { + super(random); this.location = location; this.scale = scale; this.shape = shape; - this.random = random; } /** @@ -181,4 +194,41 @@ public class GeneralizedLogisticDistribution implements Distribution { public String toString() { return "GeneralizedLogisticDistribution(location=" + location + ", scale=" + scale + ", shape=" + shape + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double location, scale, shape; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locationP = new DoubleParameter(LOCATION_ID); + if (config.grab(locationP)) { + location = locationP.doubleValue(); + } + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if (config.grab(scaleP)) { + scale = scaleP.doubleValue(); + } + + DoubleParameter shapeP = new DoubleParameter(SHAPE_ID); + if (config.grab(shapeP)) { + shape = shapeP.doubleValue(); + } + } + + @Override + protected GeneralizedLogisticDistribution makeInstance() { + return new GeneralizedLogisticDistribution(location, scale, shape, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GumbelDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GumbelDistribution.java index 15b4ca24..9f42b7e2 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GumbelDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/GumbelDistribution.java @@ -25,12 +25,16 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Gumbel distribution, also known as Log-Weibull distribution. * * @author Erich Schubert */ -public class GumbelDistribution implements Distribution { +public class GumbelDistribution extends AbstractDistribution { /** * Mode parameter mu. */ @@ -42,18 +46,26 @@ public class GumbelDistribution implements Distribution { double beta; /** - * Random number generator. + * Constructor. + * + * @param mu Mode + * @param beta Shape */ - Random random; + public GumbelDistribution(double mu, double beta) { + this(mu, beta, (Random) null); + } /** * Constructor. * * @param mu Mode * @param beta Shape + * @param random Random number generator */ - public GumbelDistribution(double mu, double beta) { - this(mu, beta, null); + public GumbelDistribution(double mu, double beta, Random random) { + super(random); + this.mu = mu; + this.beta = beta; } /** @@ -63,11 +75,10 @@ public class GumbelDistribution implements Distribution { * @param beta Shape * @param random Random number generator */ - public GumbelDistribution(double mu, double beta, Random random) { - super(); + public GumbelDistribution(double mu, double beta, RandomFactory random) { + super(random); this.mu = mu; this.beta = beta; - this.random = random; } /** @@ -131,4 +142,36 @@ public class GumbelDistribution implements Distribution { public String toString() { return "GumbelDistribution(mu=" + mu + ", beta=" + beta + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double mean, shape; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter meanP = new DoubleParameter(LOCATION_ID); + if (config.grab(meanP)) { + mean = meanP.doubleValue(); + } + + DoubleParameter shapeP = new DoubleParameter(SHAPE_ID); + if (config.grab(shapeP)) { + shape = shapeP.doubleValue(); + } + } + + @Override + protected GumbelDistribution makeInstance() { + return new GumbelDistribution(mean, shape, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/HaltonUniformDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/HaltonUniformDistribution.java index 145744db..c16bb498 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/HaltonUniformDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/HaltonUniformDistribution.java @@ -27,7 +27,10 @@ import java.util.Random; import de.lmu.ifi.dbs.elki.math.MathUtil; import de.lmu.ifi.dbs.elki.math.Primes; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Halton sequences are a pseudo-uniform distribution. The data is actually too @@ -162,7 +165,6 @@ public class HaltonUniformDistribution implements Distribution { * @param max Maximum value */ public HaltonUniformDistribution(double min, double max) { - // TODO: use different starting primes? this(min, max, new Random()); } @@ -175,11 +177,22 @@ public class HaltonUniformDistribution implements Distribution { * @param rnd Random generator */ public HaltonUniformDistribution(double min, double max, Random rnd) { - // TODO: use different starting primes? this(min, max, choosePrime(rnd), rnd.nextDouble()); } /** + * Constructor for a halton pseudo uniform distribution on the interval [min, + * max[ + * + * @param min Minimum value + * @param max Maximum value + * @param rnd Random generator + */ + public HaltonUniformDistribution(double min, double max, RandomFactory rnd) { + this(min, max, rnd.getRandom()); + } + + /** * Choose a random prime. We try to avoid the later primes, as they are known * to cause too correlated data. * @@ -310,4 +323,38 @@ public class HaltonUniformDistribution implements Distribution { public double getMax() { return max; } + + /** + * Parameterization class + * + * TODO: allow manual parameterization of sequence parameters! + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double min, max; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter minP = new DoubleParameter(UniformDistribution.Parameterizer.MIN_ID); + if (config.grab(minP)) { + min = minP.doubleValue(); + } + + DoubleParameter maxP = new DoubleParameter(UniformDistribution.Parameterizer.MAX_ID); + if (config.grab(maxP)) { + max = maxP.doubleValue(); + } + } + + @Override + protected HaltonUniformDistribution makeInstance() { + return new HaltonUniformDistribution(min, max, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/KappaDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/KappaDistribution.java index 9414767c..156bf325 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/KappaDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/KappaDistribution.java @@ -24,6 +24,11 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; */ import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Kappa distribution, by Hosking. * @@ -31,7 +36,7 @@ import java.util.Random; * * @author Erich Schubert */ -public class KappaDistribution implements Distribution { +public class KappaDistribution extends AbstractDistribution { /** * Parameters: location and scale */ @@ -43,11 +48,6 @@ public class KappaDistribution implements Distribution { double shape1, shape2; /** - * Random number generator - */ - Random random; - - /** * Constructor. * * @param location Location @@ -56,7 +56,7 @@ public class KappaDistribution implements Distribution { * @param shape2 Shape parameter */ public KappaDistribution(double location, double scale, double shape1, double shape2) { - this(location, scale, shape1, shape2, null); + this(location, scale, shape1, shape2, (Random) null); } /** @@ -69,19 +69,43 @@ public class KappaDistribution implements Distribution { * @param random Random number generator */ public KappaDistribution(double location, double scale, double shape1, double shape2, Random random) { - super(); + super(random); this.location = location; this.scale = scale; this.shape1 = shape1; this.shape2 = shape2; - this.random = random; - if(shape2 >= 0.) { - if(shape1 < -1.) { + if (shape2 >= 0.) { + if (shape1 < -1.) { throw new ArithmeticException("Invalid shape1 parameter - must be greater than -1 if shape2 >= 0.!"); } + } else { + if (shape1 < 1. || shape1 > 1. / shape2) { + throw new ArithmeticException("Invalid shape1 parameter - must be -1 to +1/shape2 if shape2 < 0.!"); + } } - else { - if(shape1 < 1. || shape1 > 1. / shape2) { + } + + /** + * Constructor. + * + * @param location Location + * @param scale Scale + * @param shape1 Shape parameter + * @param shape2 Shape parameter + * @param random Random number generator + */ + public KappaDistribution(double location, double scale, double shape1, double shape2, RandomFactory random) { + super(random); + this.location = location; + this.scale = scale; + this.shape1 = shape1; + this.shape2 = shape2; + if (shape2 >= 0.) { + if (shape1 < -1.) { + throw new ArithmeticException("Invalid shape1 parameter - must be greater than -1 if shape2 >= 0.!"); + } + } else { + if (shape1 < 1. || shape1 > 1. / shape2) { throw new ArithmeticException("Invalid shape1 parameter - must be -1 to +1/shape2 if shape2 < 0.!"); } } @@ -100,9 +124,9 @@ public class KappaDistribution implements Distribution { public static double pdf(double val, double loc, double scale, double shape1, double shape2) { final double c = cdf(val, loc, scale, shape1, shape2); val = (val - loc) / scale; - if(shape1 != 0.) { + if (shape1 != 0.) { val = 1 - shape1 * val; - if(val < 1e-15) { + if (val < 1e-15) { return 0.; } val = (1. - 1. / shape1) * Math.log(val); @@ -128,24 +152,22 @@ public class KappaDistribution implements Distribution { */ public static double cdf(double val, double loc, double scale, double shape1, double shape2) { val = (val - loc) / scale; - if(shape1 != 0.) { + if (shape1 != 0.) { double tmp = 1. - shape1 * val; - if(tmp < 1e-15) { + if (tmp < 1e-15) { return (shape1 < 0.) ? 0. : 1.; } val = Math.exp(Math.log(tmp) / shape1); - } - else { + } else { val = Math.exp(-val); } - if(shape2 != 0.) { + if (shape2 != 0.) { double tmp = 1. - shape2 * val; - if(tmp < 1e-15) { + if (tmp < 1e-15) { return 0.; } val = Math.exp(Math.log(tmp) / shape2); - } - else { + } else { val = Math.exp(-val); } return val; @@ -167,39 +189,36 @@ public class KappaDistribution implements Distribution { * @return Quantile */ public static double quantile(double val, double loc, double scale, double shape1, double shape2) { - if(!(val >= 0.) || !(val <= 1.)) { + if (!(val >= 0.) || !(val <= 1.)) { return Double.NaN; } - if(val == 0.) { - if(shape2 <= 0.) { - if(shape1 < 0.) { + if (val == 0.) { + if (shape2 <= 0.) { + if (shape1 < 0.) { return loc + scale / shape1; - } - else { + } else { return Double.NEGATIVE_INFINITY; } - } - else { - if(shape1 != 0.) { + } else { + if (shape1 != 0.) { return loc + scale / shape1 * (1. - Math.pow(shape2, -shape1)); - } - else { + } else { return loc + scale * Math.log(shape2); } } } - if(val == 1.) { - if(shape1 <= 0.) { + if (val == 1.) { + if (shape1 <= 0.) { return Double.NEGATIVE_INFINITY; } return loc + scale / shape1; } val = -Math.log(val); - if(shape2 != 0.) { + if (shape2 != 0.) { val = (1 - Math.exp(-shape2 * val)) / shape2; } val = -Math.log(val); - if(shape1 != 0.) { + if (shape1 != 0.) { val = (1 - Math.exp(-shape1 * val)) / shape1; } return loc + scale * val; @@ -220,4 +239,56 @@ public class KappaDistribution implements Distribution { public String toString() { return "KappaDistribution(location=" + location + ", scale=" + scale + ", shape1=" + shape1 + ", shape2=" + shape2 + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * First shape parameter. + */ + public static final OptionID SHAPE1_ID = new OptionID("distribution.kappa.shape1", "First shape parameter of kappa distribution."); + + /** + * Second shape parameter. + */ + public static final OptionID SHAPE2_ID = new OptionID("distribution.kappa.shape2", "Second shape parameter of kappa distribution."); + + /** Parameters. */ + double location, scale, shape1, shape2; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locationP = new DoubleParameter(LOCATION_ID); + if (config.grab(locationP)) { + location = locationP.doubleValue(); + } + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if (config.grab(scaleP)) { + scale = scaleP.doubleValue(); + } + + DoubleParameter shape1P = new DoubleParameter(SHAPE1_ID); + if (config.grab(shape1P)) { + shape1 = shape1P.doubleValue(); + } + + DoubleParameter shape2P = new DoubleParameter(SHAPE2_ID); + if (config.grab(shape2P)) { + shape2 = shape2P.doubleValue(); + } + } + + @Override + protected KappaDistribution makeInstance() { + return new KappaDistribution(location, scale, shape1, shape2, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LaplaceDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LaplaceDistribution.java index eb238a20..18a6ffbe 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LaplaceDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LaplaceDistribution.java @@ -26,6 +26,10 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Laplace distribution also known as double exponential distribution @@ -33,12 +37,7 @@ import de.lmu.ifi.dbs.elki.utilities.Alias; * @author Erich Schubert */ @Alias("DoubleExponentialDistribution") -public class LaplaceDistribution implements Distribution { - /** - * Random generator. - */ - Random rnd; - +public class LaplaceDistribution extends AbstractDistribution { /** * Rate, inverse of mean */ @@ -55,7 +54,7 @@ public class LaplaceDistribution implements Distribution { * @param rate Rate parameter (1/scale) */ public LaplaceDistribution(double rate) { - this(rate, 0.0, null); + this(rate, 0., (Random) null); } /** @@ -65,7 +64,7 @@ public class LaplaceDistribution implements Distribution { * @param location Location parameter */ public LaplaceDistribution(double rate, double location) { - this(rate, location, null); + this(rate, location, (Random) null); } /** @@ -75,7 +74,7 @@ public class LaplaceDistribution implements Distribution { * @param random Random generator */ public LaplaceDistribution(double rate, Random random) { - this(rate, 0.0, random); + this(rate, 0., random); } /** @@ -86,10 +85,22 @@ public class LaplaceDistribution implements Distribution { * @param random Random generator */ public LaplaceDistribution(double rate, double location, Random random) { - super(); + super(random); + this.rate = rate; + this.location = location; + } + + /** + * Constructor. + * + * @param rate Rate parameter (1/scale) + * @param location Location parameter + * @param random Random generator + */ + public LaplaceDistribution(double rate, double location, RandomFactory random) { + super(random); this.rate = rate; this.location = location; - this.rnd = random; } @Override @@ -157,7 +168,7 @@ public class LaplaceDistribution implements Distribution { */ @Override public double nextRandom() { - double val = rnd.nextDouble(); + double val = random.nextDouble(); if (val < .5) { return Math.log(2 * val) / rate + location; } else { @@ -169,4 +180,41 @@ public class LaplaceDistribution implements Distribution { public String toString() { return "LaplaceDistribution(rate=" + rate + ", location=" + location + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Shape parameter gamma. + */ + public static final OptionID RATE_ID = new OptionID("distribution.laplace.rate", "Laplace distribution rate (lambda) parameter (inverse of scale)."); + + /** Parameters. */ + double location, rate; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter locP = new DoubleParameter(LOCATION_ID); + if (config.grab(locP)) { + location = locP.doubleValue(); + } + + DoubleParameter rateP = new DoubleParameter(RATE_ID); + if (config.grab(rateP)) { + rate = rateP.doubleValue(); + } + } + + @Override + protected LaplaceDistribution makeInstance() { + return new LaplaceDistribution(rate, location, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaAlternateDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaAlternateDistribution.java index 496e6867..90902ae0 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaAlternateDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaAlternateDistribution.java @@ -25,6 +25,11 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Alternate Log-Gamma Distribution, with random generation and density * functions. @@ -35,7 +40,7 @@ import java.util.Random; * * @author Erich Schubert */ -public class LogGammaAlternateDistribution implements Distribution { +public class LogGammaAlternateDistribution extends AbstractDistribution { /** * Alpha == k. */ @@ -52,9 +57,23 @@ public class LogGammaAlternateDistribution implements Distribution { private final double shift; /** - * The random generator. + * Constructor for Gamma distribution. + * + * @param k k, alpha aka. "shape" parameter + * @param shift Location offset + * @param theta Theta = 1.0/Beta aka. "scaling" parameter + * @param random Random generator */ - private Random random; + public LogGammaAlternateDistribution(double k, double theta, double shift, Random random) { + super(random); + if (!(k > 0.0) || !(theta > 0.0)) { // Note: also tests for NaNs! + throw new IllegalArgumentException("Invalid parameters for Gamma distribution: " + k + " " + theta); + } + + this.k = k; + this.theta = theta; + this.shift = shift; + } /** * Constructor for Gamma distribution. @@ -64,8 +83,8 @@ public class LogGammaAlternateDistribution implements Distribution { * @param theta Theta = 1.0/Beta aka. "scaling" parameter * @param random Random generator */ - public LogGammaAlternateDistribution(double k, double theta, double shift, Random random) { - super(); + public LogGammaAlternateDistribution(double k, double theta, double shift, RandomFactory random) { + super(random); if (!(k > 0.0) || !(theta > 0.0)) { // Note: also tests for NaNs! throw new IllegalArgumentException("Invalid parameters for Gamma distribution: " + k + " " + theta); } @@ -73,7 +92,6 @@ public class LogGammaAlternateDistribution implements Distribution { this.k = k; this.theta = theta; this.shift = shift; - this.random = random; } /** @@ -84,7 +102,7 @@ public class LogGammaAlternateDistribution implements Distribution { * @param shift Location offset */ public LogGammaAlternateDistribution(double k, double theta, double shift) { - this(k, theta, shift, null); + this(k, theta, shift, (Random) null); } @Override @@ -206,4 +224,46 @@ public class LogGammaAlternateDistribution implements Distribution { public static double quantile(double p, double k, double theta, double shift) { return Math.log(GammaDistribution.quantile(p, k, 1.)) / theta + shift; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Shifting offset parameter. + */ + public static final OptionID SHIFT_ID = new OptionID("distribution.loggamma.shift", "Shift offset parameter."); + + /** Parameters. */ + double k, theta, shift; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter kP = new DoubleParameter(GammaDistribution.Parameterizer.K_ID); + if (config.grab(kP)) { + k = kP.doubleValue(); + } + + DoubleParameter thetaP = new DoubleParameter(GammaDistribution.Parameterizer.THETA_ID); + if (config.grab(thetaP)) { + theta = thetaP.doubleValue(); + } + + DoubleParameter shiftP = new DoubleParameter(SHIFT_ID); + if (config.grab(shiftP)) { + shift = shiftP.doubleValue(); + } + } + + @Override + protected LogGammaAlternateDistribution makeInstance() { + return new LogGammaAlternateDistribution(k, theta, shift, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaDistribution.java index db3a2b3f..76b10dde 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogGammaDistribution.java @@ -25,6 +25,11 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Log-Gamma Distribution, with random generation and density functions. * @@ -34,7 +39,7 @@ import java.util.Random; * * @author Erich Schubert */ -public class LogGammaDistribution implements Distribution { +public class LogGammaDistribution extends AbstractDistribution { /** * Alpha == k. */ @@ -51,9 +56,23 @@ public class LogGammaDistribution implements Distribution { private final double shift; /** - * The random generator. + * Constructor for Gamma distribution. + * + * @param k k, alpha aka. "shape" parameter + * @param shift Location offset + * @param theta Theta = 1.0/Beta aka. "scaling" parameter + * @param random Random generator */ - private Random random; + public LogGammaDistribution(double k, double theta, double shift, Random random) { + super(random); + if (!(k > 0.0) || !(theta > 0.0)) { // Note: also tests for NaNs! + throw new IllegalArgumentException("Invalid parameters for Gamma distribution: " + k + " " + theta); + } + + this.k = k; + this.theta = theta; + this.shift = shift; + } /** * Constructor for Gamma distribution. @@ -63,8 +82,8 @@ public class LogGammaDistribution implements Distribution { * @param theta Theta = 1.0/Beta aka. "scaling" parameter * @param random Random generator */ - public LogGammaDistribution(double k, double theta, double shift, Random random) { - super(); + public LogGammaDistribution(double k, double theta, double shift, RandomFactory random) { + super(random); if (!(k > 0.0) || !(theta > 0.0)) { // Note: also tests for NaNs! throw new IllegalArgumentException("Invalid parameters for Gamma distribution: " + k + " " + theta); } @@ -72,7 +91,6 @@ public class LogGammaDistribution implements Distribution { this.k = k; this.theta = theta; this.shift = shift; - this.random = random; } /** @@ -83,7 +101,7 @@ public class LogGammaDistribution implements Distribution { * @param shift Location offset */ public LogGammaDistribution(double k, double theta, double shift) { - this(k, theta, shift, null); + this(k, theta, shift, (Random) null); } @Override @@ -191,4 +209,46 @@ public class LogGammaDistribution implements Distribution { public static double quantile(double p, double k, double theta, double shift) { return Math.exp(GammaDistribution.quantile(p, k, theta)) + shift; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Shifting offset parameter. + */ + public static final OptionID SHIFT_ID = new OptionID("distribution.loggamma.shift", "Shift offset parameter."); + + /** Parameters. */ + double k, theta, shift; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter kP = new DoubleParameter(GammaDistribution.Parameterizer.K_ID); + if (config.grab(kP)) { + k = kP.doubleValue(); + } + + DoubleParameter thetaP = new DoubleParameter(GammaDistribution.Parameterizer.THETA_ID); + if (config.grab(thetaP)) { + theta = thetaP.doubleValue(); + } + + DoubleParameter shiftP = new DoubleParameter(SHIFT_ID); + if (config.grab(shiftP)) { + shift = shiftP.doubleValue(); + } + } + + @Override + protected LogGammaDistribution makeInstance() { + return new LogGammaDistribution(k, theta, shift, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogLogisticDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogLogisticDistribution.java index cb75561d..fe8557b3 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogLogisticDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogLogisticDistribution.java @@ -24,30 +24,44 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; */ import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Log-Logistic distribution also known as Fisk distribution. * * @author Erich Schubert */ -public class LogLogisticDistribution implements Distribution { +@Alias({ "fisk", "loglog" }) +public class LogLogisticDistribution extends AbstractDistribution { /** * Parameters: scale and shape */ double scale, shape; /** - * Random number generator + * Constructor. + * + * @param scale Scale + * @param shape Shape */ - Random random; + public LogLogisticDistribution(double scale, double shape) { + this(scale, shape, (Random) null); + } /** * Constructor. * * @param scale Scale * @param shape Shape + * @param random Random number generator */ - public LogLogisticDistribution(double scale, double shape) { - this(scale, shape, null); + public LogLogisticDistribution(double scale, double shape, Random random) { + super(random); + this.scale = scale; + this.shape = shape; } /** @@ -57,11 +71,10 @@ public class LogLogisticDistribution implements Distribution { * @param shape Shape * @param random Random number generator */ - public LogLogisticDistribution(double scale, double shape, Random random) { - super(); + public LogLogisticDistribution(double scale, double shape, RandomFactory random) { + super(random); this.scale = scale; this.shape = shape; - this.random = random; } /** @@ -73,7 +86,7 @@ public class LogLogisticDistribution implements Distribution { * @return PDF */ public static double pdf(double val, double scale, double shape) { - if(val < 0) { + if (val < 0) { return 0; } val = Math.abs(val / scale); @@ -96,7 +109,7 @@ public class LogLogisticDistribution implements Distribution { * @return CDF */ public static double cdf(double val, double scale, double shape) { - if(val < 0) { + if (val < 0) { return 0; } return 1. / (1. + Math.pow(val / scale, -shape)); @@ -134,4 +147,36 @@ public class LogLogisticDistribution implements Distribution { public String toString() { return "LogLogisticDistribution(scale=" + scale + ", shape=" + shape + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double scale, shape; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if (config.grab(scaleP)) { + scale = scaleP.doubleValue(); + } + + DoubleParameter shapeP = new DoubleParameter(SHAPE_ID); + if (config.grab(shapeP)) { + shape = shapeP.doubleValue(); + } + } + + @Override + protected LogLogisticDistribution makeInstance() { + return new LogLogisticDistribution(scale, shape, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogNormalDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogNormalDistribution.java index 4c3d9aa0..ca2fbbab 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogNormalDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogNormalDistribution.java @@ -26,6 +26,11 @@ import java.util.Random; import de.lmu.ifi.dbs.elki.math.MathUtil; import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Log-Normal distribution. @@ -40,7 +45,7 @@ import de.lmu.ifi.dbs.elki.utilities.Alias; * @author Erich Schubert */ @Alias({ "lognormal" }) -public class LogNormalDistribution implements Distribution { +public class LogNormalDistribution extends AbstractDistribution { /** * Mean value for the generator */ @@ -57,9 +62,19 @@ public class LogNormalDistribution implements Distribution { private double shift = 0.; /** - * The random generator. + * Constructor for Log-Normal distribution + * + * @param logmean Mean + * @param logstddev Standard Deviation + * @param shift Shifting offset + * @param random Random generator */ - private Random random; + public LogNormalDistribution(double logmean, double logstddev, double shift, Random random) { + super(random); + this.logmean = logmean; + this.logstddev = logstddev; + this.shift = shift; + } /** * Constructor for Log-Normal distribution @@ -69,12 +84,11 @@ public class LogNormalDistribution implements Distribution { * @param shift Shifting offset * @param random Random generator */ - public LogNormalDistribution(double logmean, double logstddev, double shift, Random random) { - super(); + public LogNormalDistribution(double logmean, double logstddev, double shift, RandomFactory random) { + super(random); this.logmean = logmean; this.logstddev = logstddev; this.shift = shift; - this.random = random; } /** @@ -85,7 +99,7 @@ public class LogNormalDistribution implements Distribution { * @param shift Shifting offset */ public LogNormalDistribution(double logmean, double logstddev, double shift) { - this(logmean, logstddev, shift, null); + this(logmean, logstddev, shift, (Random) null); } @Override @@ -117,7 +131,7 @@ public class LogNormalDistribution implements Distribution { * @return PDF of the given normal distribution at x. */ public static double pdf(double x, double mu, double sigma) { - if (x <= 0.) { + if(x <= 0.) { return 0.; } final double x_mu = Math.log(x) - mu; @@ -134,7 +148,7 @@ public class LogNormalDistribution implements Distribution { * @return The CDF of the given normal distribution at x. */ public static double cdf(double x, double mu, double sigma) { - if (x <= 0.) { + if(x <= 0.) { return 0.; } return .5 * (1 + NormalDistribution.erf((Math.log(x) - mu) / (MathUtil.SQRT2 * sigma))); @@ -162,4 +176,57 @@ public class LogNormalDistribution implements Distribution { public String toString() { return "LogNormalDistribution(logmean=" + logmean + ", logstddev=" + logstddev + ", shift=" + shift + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * LogMean parameter + */ + public static final OptionID LOGMEAN_ID = new OptionID("distribution.lognormal.logmean", "Mean of the distribution before logscaling."); + + /** + * LogScale parameter + */ + public static final OptionID LOGSTDDEV_ID = new OptionID("distribution.lognormal.logstddev", "Standard deviation of the distribution before logscaling."); + + /** + * Shift parameter + */ + public static final OptionID SHIFT_ID = new OptionID("distribution.lognormal.shift", "Shifting offset, so the distribution does not begin at 0."); + + /** Parameters. */ + double shift, logmean, logsigma; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter logmeanP = new DoubleParameter(LOGMEAN_ID); + if(config.grab(logmeanP)) { + logmean = logmeanP.doubleValue(); + } + + DoubleParameter logsigmaP = new DoubleParameter(LOGSTDDEV_ID); + logsigmaP.addConstraint(CommonConstraints.GREATER_THAN_ZERO_DOUBLE); + if(config.grab(logsigmaP)) { + logsigma = logsigmaP.doubleValue(); + } + + DoubleParameter shiftP = new DoubleParameter(SHIFT_ID, 0.); + if(config.grab(shiftP)) { + shift = shiftP.doubleValue(); + } + } + + @Override + protected LogNormalDistribution makeInstance() { + return new LogNormalDistribution(logmean, logsigma, shift, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogisticDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogisticDistribution.java index 052847d6..12307a36 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogisticDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/LogisticDistribution.java @@ -25,31 +25,44 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; import de.lmu.ifi.dbs.elki.math.MathUtil; +import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Logistic distribution. * * @author Erich Schubert */ -public class LogisticDistribution implements Distribution { +@Alias({ "log" }) +public class LogisticDistribution extends AbstractDistribution { /** * Parameters: location and scale */ double location, scale; /** - * Random number generator + * Constructor. + * + * @param location Location + * @param scale Scale */ - Random random; + public LogisticDistribution(double location, double scale) { + this(location, scale, (Random) null); + } /** * Constructor. * * @param location Location * @param scale Scale + * @param random Random number generator */ - public LogisticDistribution(double location, double scale) { - this(location, scale, null); + public LogisticDistribution(double location, double scale, Random random) { + super(random); + this.location = location; + this.scale = scale; } /** @@ -59,11 +72,10 @@ public class LogisticDistribution implements Distribution { * @param scale Scale * @param random Random number generator */ - public LogisticDistribution(double location, double scale, Random random) { - super(); + public LogisticDistribution(double location, double scale, RandomFactory random) { + super(random); this.location = location; this.scale = scale; - this.random = random; } /** @@ -183,4 +195,36 @@ public class LogisticDistribution implements Distribution { public String toString() { return "LogisticDistribution(location=" + location + ", scale=" + scale + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double location, scale; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if (config.grab(scaleP)) { + scale = scaleP.doubleValue(); + } + + DoubleParameter locationP = new DoubleParameter(LOCATION_ID); + if (config.grab(locationP)) { + location = locationP.doubleValue(); + } + } + + @Override + protected LogisticDistribution makeInstance() { + return new LogisticDistribution(location, scale, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/NormalDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/NormalDistribution.java index c4ae7b6c..0a0d3d4e 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/NormalDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/NormalDistribution.java @@ -27,6 +27,10 @@ import java.util.Random; import de.lmu.ifi.dbs.elki.math.MathUtil; import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Gaussian distribution aka normal distribution @@ -34,7 +38,7 @@ import de.lmu.ifi.dbs.elki.utilities.Alias; * @author Erich Schubert */ @Alias({ "GaussianDistribution", "normal", "gauss" }) -public class NormalDistribution implements Distribution { +public class NormalDistribution extends AbstractDistribution { /** * Coefficients for erf approximation. * @@ -123,9 +127,17 @@ public class NormalDistribution implements Distribution { private double stddev; /** - * The random generator. + * Constructor for Gaussian distribution + * + * @param mean Mean + * @param stddev Standard Deviation + * @param random Random generator */ - private Random random; + public NormalDistribution(double mean, double stddev, RandomFactory random) { + super(random); + this.mean = mean; + this.stddev = stddev; + } /** * Constructor for Gaussian distribution @@ -135,10 +147,9 @@ public class NormalDistribution implements Distribution { * @param random Random generator */ public NormalDistribution(double mean, double stddev, Random random) { - super(); + super(random); this.mean = mean; this.stddev = stddev; - this.random = random; } /** @@ -148,7 +159,7 @@ public class NormalDistribution implements Distribution { * @param stddev Standard Deviation */ public NormalDistribution(double mean, double stddev) { - this(mean, stddev, new Random()); + this(mean, stddev, (Random) null); } @Override @@ -368,4 +379,37 @@ public class NormalDistribution implements Distribution { return (((((ERFINV_A[0] * r + ERFINV_A[1]) * r + ERFINV_A[2]) * r + ERFINV_A[3]) * r + ERFINV_A[4]) * r + ERFINV_A[5]) * q / (((((ERFINV_B[0] * r + ERFINV_B[1]) * r + ERFINV_B[2]) * r + ERFINV_B[3]) * r + ERFINV_B[4]) * r + 1); } } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double mu, sigma; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter muP = new DoubleParameter(LOCATION_ID); + if (config.grab(muP)) { + mu = muP.doubleValue(); + } + + DoubleParameter sigmaP = new DoubleParameter(SCALE_ID); + sigmaP.addConstraint(CommonConstraints.GREATER_THAN_ZERO_DOUBLE); + if (config.grab(sigmaP)) { + sigma = sigmaP.doubleValue(); + } + } + + @Override + protected NormalDistribution makeInstance() { + return new NormalDistribution(mu, sigma, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/PoissonDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/PoissonDistribution.java index f6b2e0ca..b6b70b34 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/PoissonDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/PoissonDistribution.java @@ -22,10 +22,18 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ +import java.util.Random; + import de.lmu.ifi.dbs.elki.math.MathUtil; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages; import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter; /** * INCOMPLETE implementation of the poisson distribution. @@ -40,7 +48,7 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; * * @author Erich Schubert */ -public class PoissonDistribution implements Distribution { +public class PoissonDistribution extends AbstractDistribution { /** * Number of tries */ @@ -108,86 +116,91 @@ public class PoissonDistribution implements Distribution { /** * Constructor. * - * Private: API not yet completely implemented! - * * @param n Number of tries * @param p Success probability */ public PoissonDistribution(int n, double p) { - super(); + this(n, p, (Random) null); + } + + /** + * Constructor. + * + * @param n Number of tries + * @param p Success probability + * @param random Random generator + */ + public PoissonDistribution(int n, double p, Random random) { + super(random); + this.n = n; + this.p = p; + } + + /** + * Constructor. + * + * @param n Number of tries + * @param p Success probability + * @param random Random generator + */ + public PoissonDistribution(int n, double p, RandomFactory random) { + super(random); this.n = n; this.p = p; } /** - * Poisson PMF for integer values. + * Poisson probability mass function (PMF) for integer values. * * @param x integer values * @return Probability */ - @Reference(title = "Fast and accurate computation of binomial probabilities", authors = "C. Loader", booktitle = "", url = "http://projects.scipy.org/scipy/raw-attachment/ticket/620/loader2000Fast.pdf") public double pmf(int x) { - // Invalid values - if (x < 0 || x > n) { - return 0.0; - } - // Extreme probabilities - if (p <= 0d) { - return x == 0 ? 1.0 : 0.0; - } - if (p >= 1d) { - return x == n ? 1.0 : 0.0; - } - // Extreme values of x - if (x == 0) { - if (p < 0.1) { - return Math.exp(-devianceTerm(n, n * (1.0 - p)) - n * p); - } else { - return Math.exp(n * Math.log(1.0 - p)); - } - } - if (x == n) { - if (p > 0.9) { - return Math.exp(-devianceTerm(n, n * p) - n * (1 - p)); - } else { - return Math.exp(n * Math.log(p)); - } - } - - final double lc = stirlingError(n) - stirlingError(x) - stirlingError(n - x) - devianceTerm(x, n * p) - devianceTerm(n - x, n * (1.0 - p)); - final double f = (MathUtil.TWOPI * x * (n - x)) / n; - return Math.exp(lc) / Math.sqrt(f); + return pmf(x, n, p); } @Override - @Reference(title = "Fast and accurate computation of binomial probabilities", authors = "C. Loader", booktitle = "", url = "http://projects.scipy.org/scipy/raw-attachment/ticket/620/loader2000Fast.pdf") public double pdf(double x) { + // FIXME: return 0 for non-integer x? + return pmf(x, n, p); + } + + /** + * Poisson probability mass function (PMF) for integer values. + * + * @param x integer values + * @return Probability + */ + @Reference(title = "Fast and accurate computation of binomial probabilities", authors = "C. Loader", booktitle = "", url = "http://projects.scipy.org/scipy/raw-attachment/ticket/620/loader2000Fast.pdf") + public static double pmf(double x, int n, double p) { // Invalid values - if (x < 0 || x > n) { - return 0.0; + if(x < 0 || x > n) { + return 0.; } // Extreme probabilities - if (p <= 0d) { - return x == 0 ? 1.0 : 0.0; + if(p <= 0.) { + return x == 0 ? 1. : 0.; } - if (p >= 1d) { - return x == n ? 1.0 : 0.0; + if(p >= 1.) { + return x == n ? 1. : 0.; } final double q = 1 - p; // FIXME: check for x to be integer, return 0 otherwise? // Extreme values of x - if (x == 0) { - if (p < 0.1) { + if(x == 0) { + if(p < .1) { return Math.exp(-devianceTerm(n, n * q) - n * p); - } else { + } + else { return Math.exp(n * Math.log(q)); } } - if (x == n) { - if (p > 0.9) { + if(x == n) { + if(p > .9) { return Math.exp(-devianceTerm(n, n * p) - n * q); - } else { + } + else { return Math.exp(n * Math.log(p)); } } @@ -224,15 +237,16 @@ public class PoissonDistribution implements Distribution { * @return pdf */ public static double poissonPDFm1(double x_plus_1, double lambda) { - if (Double.isInfinite(lambda)) { + if(Double.isInfinite(lambda)) { return 0.; } - if (x_plus_1 > 1) { + if(x_plus_1 > 1) { return rawProbability(x_plus_1 - 1, lambda); } - if (lambda > Math.abs(x_plus_1 - 1) * MathUtil.LOG2 * Double.MAX_EXPONENT / 1e-14) { + if(lambda > Math.abs(x_plus_1 - 1) * MathUtil.LOG2 * Double.MAX_EXPONENT / 1e-14) { return Math.exp(-lambda - GammaDistribution.logGamma(x_plus_1)); - } else { + } + else { return rawProbability(x_plus_1, lambda) * (x_plus_1 / lambda); } } @@ -247,15 +261,16 @@ public class PoissonDistribution implements Distribution { * @return pdf */ public static double logpoissonPDFm1(double x_plus_1, double lambda) { - if (Double.isInfinite(lambda)) { + if(Double.isInfinite(lambda)) { return Double.NEGATIVE_INFINITY; } - if (x_plus_1 > 1) { + if(x_plus_1 > 1) { return rawLogProbability(x_plus_1 - 1, lambda); } - if (lambda > Math.abs(x_plus_1 - 1) * MathUtil.LOG2 * Double.MAX_EXPONENT / 1e-14) { + if(lambda > Math.abs(x_plus_1 - 1) * MathUtil.LOG2 * Double.MAX_EXPONENT / 1e-14) { return -lambda - GammaDistribution.logGamma(x_plus_1); - } else { + } + else { return rawLogProbability(x_plus_1, lambda) + Math.log(x_plus_1 / lambda); } } @@ -271,18 +286,18 @@ public class PoissonDistribution implements Distribution { @Reference(title = "Fast and accurate computation of binomial probabilities", authors = "C. Loader", booktitle = "", url = "http://projects.scipy.org/scipy/raw-attachment/ticket/620/loader2000Fast.pdf") private static double stirlingError(int n) { // Try to use a table value: - if (n < 16) { + if(n < 16) { return STIRLING_EXACT_ERROR[n << 1]; } final double nn = n * n; // Use the appropriate number of terms - if (n > 500) { + if(n > 500) { return (S0 - S1 / nn) / n; } - if (n > 80) { + if(n > 80) { return ((S0 - (S1 - S2 / nn)) / nn) / n; } - if (n > 35) { + if(n > 35) { return ((S0 - (S1 - (S2 - S3 / nn) / nn) / nn) / n); } return ((S0 - (S1 - (S2 - (S3 - S4 / nn) / nn) / nn) / nn) / n); @@ -298,23 +313,24 @@ public class PoissonDistribution implements Distribution { */ @Reference(title = "Fast and accurate computation of binomial probabilities", authors = "C. Loader", booktitle = "", url = "http://projects.scipy.org/scipy/raw-attachment/ticket/620/loader2000Fast.pdf") private static double stirlingError(double n) { - if (n < 16.0) { + if(n < 16.0) { // Our table has a step size of 0.5 final double n2 = 2.0 * n; - if (Math.floor(n2) == n2) { // Exact match + if(Math.floor(n2) == n2) { // Exact match return STIRLING_EXACT_ERROR[(int) n2]; - } else { + } + else { return GammaDistribution.logGamma(n + 1.0) - (n + 0.5) * Math.log(n) + n - MathUtil.LOGSQRTTWOPI; } } final double nn = n * n; - if (n > 500.0) { + if(n > 500.0) { return (S0 - S1 / nn) / n; } - if (n > 80.0) { + if(n > 80.0) { return ((S0 - (S1 - S2 / nn)) / nn) / n; } - if (n > 35.0) { + if(n > 35.0) { return ((S0 - (S1 - (S2 - S3 / nn) / nn) / nn) / n); } return ((S0 - (S1 - (S2 - (S3 - S4 / nn) / nn) / nn) / nn) / n); @@ -331,15 +347,15 @@ public class PoissonDistribution implements Distribution { */ @Reference(title = "Fast and accurate computation of binomial probabilities", authors = "C. Loader", booktitle = "", url = "http://projects.scipy.org/scipy/raw-attachment/ticket/620/loader2000Fast.pdf") private static double devianceTerm(double x, double np) { - if (Math.abs(x - np) < 0.1 * (x + np)) { + if(Math.abs(x - np) < 0.1 * (x + np)) { final double v = (x - np) / (x + np); double s = (x - np) * v; double ej = 2.0d * x * v; - for (int j = 1;; j++) { + for(int j = 1;; j++) { ej *= v * v; final double s1 = s + ej / (2 * j + 1); - if (s1 == s) { + if(s1 == s) { return s1; } s = s1; @@ -359,17 +375,17 @@ public class PoissonDistribution implements Distribution { */ public static double rawProbability(double x, double lambda) { // Extreme lambda - if (lambda == 0) { + if(lambda == 0) { return ((x == 0) ? 1. : 0.); } // Extreme values - if (Double.isInfinite(lambda) || x < 0) { + if(Double.isInfinite(lambda) || x < 0) { return 0.; } - if (x <= lambda * Double.MIN_NORMAL) { + if(x <= lambda * Double.MIN_NORMAL) { return Math.exp(-lambda); } - if (lambda < x * Double.MIN_NORMAL) { + if(lambda < x * Double.MIN_NORMAL) { double r = -lambda + x * Math.log(lambda) - GammaDistribution.logGamma(x + 1); return Math.exp(r); } @@ -389,17 +405,17 @@ public class PoissonDistribution implements Distribution { */ public static double rawLogProbability(double x, double lambda) { // Extreme lambda - if (lambda == 0) { + if(lambda == 0) { return ((x == 0) ? 1. : Double.NEGATIVE_INFINITY); } // Extreme values - if (Double.isInfinite(lambda) || x < 0) { + if(Double.isInfinite(lambda) || x < 0) { return Double.NEGATIVE_INFINITY; } - if (x <= lambda * Double.MIN_NORMAL) { + if(x <= lambda * Double.MIN_NORMAL) { return -lambda; } - if (lambda < x * Double.MIN_NORMAL) { + if(lambda < x * Double.MIN_NORMAL) { return -lambda + x * Math.log(lambda) - GammaDistribution.logGamma(x + 1); } final double f = MathUtil.TWOPI * x; @@ -411,4 +427,56 @@ public class PoissonDistribution implements Distribution { public String toString() { return "PoissonDistribution(n=" + n + ", p=" + p + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Number of trials. + */ + public static final OptionID N_ID = new OptionID("distribution.poisson.n", "Number of trials."); + + /** + * Success probability. + */ + public static final OptionID PROB_ID = new OptionID("distribution.poisson.probability", "Success probability."); + + /** + * Number of trials. + */ + int n; + + /** + * Success probability. + */ + double p; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + IntParameter nP = new IntParameter(N_ID); + nP.addConstraint(CommonConstraints.GREATER_EQUAL_ONE_INT); + if(config.grab(nP)) { + n = nP.intValue(); + } + + DoubleParameter probP = new DoubleParameter(PROB_ID); + probP.addConstraint(CommonConstraints.GREATER_EQUAL_ZERO_DOUBLE); + probP.addConstraint(CommonConstraints.LESS_EQUAL_ONE_DOUBLE); + if(config.grab(probP)) { + p = probP.doubleValue(); + } + } + + @Override + protected PoissonDistribution makeInstance() { + return new PoissonDistribution(n, p, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/RayleighDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/RayleighDistribution.java index 31faf8ed..68870f1a 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/RayleighDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/RayleighDistribution.java @@ -25,16 +25,20 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Rayleigh distribution. * * @author Erich Schubert */ -public class RayleighDistribution implements Distribution { +public class RayleighDistribution extends AbstractDistribution { /** - * Position parameter. + * Location parameter. */ - double mu = 0.0; + double mu = 0.; /** * Scale parameter. @@ -42,17 +46,12 @@ public class RayleighDistribution implements Distribution { double sigma; /** - * Random number generator. - */ - Random random; - - /** * Constructor. * * @param sigma Scale parameter */ public RayleighDistribution(double sigma) { - this(0., sigma, null); + this(0., sigma, (Random) null); } /** @@ -62,7 +61,7 @@ public class RayleighDistribution implements Distribution { * @param sigma Scale parameter */ public RayleighDistribution(double mu, double sigma) { - this(mu, sigma, null); + this(mu, sigma, (Random) null); } /** @@ -83,10 +82,22 @@ public class RayleighDistribution implements Distribution { * @param random Random number generator */ public RayleighDistribution(double mu, double sigma, Random random) { - super(); + super(random); + this.mu = mu; + this.sigma = sigma; + } + + /** + * Constructor. + * + * @param mu Position parameter + * @param sigma Scale parameter + * @param random Random number generator + */ + public RayleighDistribution(double mu, double sigma, RandomFactory random) { + super(random); this.mu = mu; this.sigma = sigma; - this.random = random; } @Override @@ -162,4 +173,36 @@ public class RayleighDistribution implements Distribution { public String toString() { return "RayleighDistribution(mu=" + mu + ", sigma=" + sigma + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double mean, scale; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter meanP = new DoubleParameter(LOCATION_ID, 0.); + if (config.grab(meanP)) { + mean = meanP.doubleValue(); + } + + DoubleParameter scaleP = new DoubleParameter(SCALE_ID); + if (config.grab(scaleP)) { + scale = scaleP.doubleValue(); + } + } + + @Override + protected RayleighDistribution makeInstance() { + return new RayleighDistribution(mean, scale, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/SkewGeneralizedNormalDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/SkewGeneralizedNormalDistribution.java index f04e776b..76931029 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/SkewGeneralizedNormalDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/SkewGeneralizedNormalDistribution.java @@ -26,6 +26,11 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; import de.lmu.ifi.dbs.elki.math.MathUtil; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Generalized Gaussian distribution by adding a skew term, similar to lognormal @@ -36,7 +41,7 @@ import de.lmu.ifi.dbs.elki.math.MathUtil; * * @author Erich Schubert */ -public class SkewGeneralizedNormalDistribution implements Distribution { +public class SkewGeneralizedNormalDistribution extends AbstractDistribution { /** * Mean value for the generator */ @@ -53,9 +58,19 @@ public class SkewGeneralizedNormalDistribution implements Distribution { private double skew; /** - * The random generator. + * Constructor for Gaussian distribution + * + * @param mean Mean + * @param stddev Standard Deviation + * @param skew Skew + * @param random Random generator */ - private Random random; + public SkewGeneralizedNormalDistribution(double mean, double stddev, double skew, Random random) { + super(random); + this.mean = mean; + this.stddev = stddev; + this.skew = skew; + } /** * Constructor for Gaussian distribution @@ -65,12 +80,11 @@ public class SkewGeneralizedNormalDistribution implements Distribution { * @param skew Skew * @param random Random generator */ - public SkewGeneralizedNormalDistribution(double mean, double stddev, double skew, Random random) { - super(); + public SkewGeneralizedNormalDistribution(double mean, double stddev, double skew, RandomFactory random) { + super(random); this.mean = mean; this.stddev = stddev; this.skew = skew; - this.random = random; } /** @@ -81,7 +95,7 @@ public class SkewGeneralizedNormalDistribution implements Distribution { * @param skew Skew */ public SkewGeneralizedNormalDistribution(double mean, double stddev, double skew) { - this(mean, stddev, skew, null); + this(mean, stddev, skew, (Random) null); } @Override @@ -102,7 +116,7 @@ public class SkewGeneralizedNormalDistribution implements Distribution { @Override public double nextRandom() { double y = random.nextGaussian(); - if (Math.abs(skew) > 0.) { + if(Math.abs(skew) > 0.) { y = (1. - Math.exp(-skew * y)) / skew; } return mean + stddev * y; @@ -124,7 +138,7 @@ public class SkewGeneralizedNormalDistribution implements Distribution { */ public static double pdf(double x, double mu, double sigma, double skew) { x = (x - mu) / sigma; - if (Math.abs(skew) > 0.) { + if(Math.abs(skew) > 0.) { x = -Math.log(1. - skew * x) / skew; } return MathUtil.SQRTHALF * Math.exp(-.5 * x * x) / sigma / (1 - skew * x); @@ -140,9 +154,9 @@ public class SkewGeneralizedNormalDistribution implements Distribution { */ public static double cdf(double x, double mu, double sigma, double skew) { x = (x - mu) / sigma; - if (Math.abs(skew) > 0.) { + if(Math.abs(skew) > 0.) { double tmp = 1 - skew * x; - if (tmp < 1e-15) { + if(tmp < 1e-15) { return (skew < 0.) ? 0. : 1.; } x = -Math.log(tmp) / skew; @@ -161,9 +175,52 @@ public class SkewGeneralizedNormalDistribution implements Distribution { */ public static double quantile(double x, double mu, double sigma, double skew) { x = NormalDistribution.standardNormalQuantile(x); - if (Math.abs(skew) > 0.) { + if(Math.abs(skew) > 0.) { x = (1. - Math.exp(-skew * x)) / skew; } return mu + sigma * x; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Skew parameter + */ + public static final OptionID SKEW_ID = new OptionID("distribution.skewgnormal.skew", "Skew of the distribution."); + + /** Parameters. */ + double mean, sigma, skew; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter meanP = new DoubleParameter(LOCATION_ID); + if(config.grab(meanP)) { + mean = meanP.doubleValue(); + } + + DoubleParameter sigmaP = new DoubleParameter(SCALE_ID); + sigmaP.addConstraint(CommonConstraints.GREATER_THAN_ZERO_DOUBLE); + if(config.grab(sigmaP)) { + sigma = sigmaP.doubleValue(); + } + + DoubleParameter skewP = new DoubleParameter(SKEW_ID); + if(config.grab(skewP)) { + skew = skewP.doubleValue(); + } + } + + @Override + protected SkewGeneralizedNormalDistribution makeInstance() { + return new SkewGeneralizedNormalDistribution(mean, sigma, skew, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/StudentsTDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/StudentsTDistribution.java index 442df2e2..ef9f06d4 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/StudentsTDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/StudentsTDistribution.java @@ -23,17 +23,23 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+import java.util.Random;
+
+import de.lmu.ifi.dbs.elki.utilities.RandomFactory;
import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages;
import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
+import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.IntParameter;
/**
* Student's t distribution.
*
- * FIXME: add quantile function!
+ * FIXME: add quantile and random function!
*
* @author Jan Brusis
*/
-public class StudentsTDistribution implements Distribution {
+public class StudentsTDistribution extends AbstractDistribution {
/**
* Degrees of freedom
*/
@@ -45,6 +51,28 @@ public class StudentsTDistribution implements Distribution { * @param v Degrees of freedom
*/
public StudentsTDistribution(int v) {
+ this(v, (Random) null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param v Degrees of freedom
+ * @param random Random generator
+ */
+ public StudentsTDistribution(int v, Random random) {
+ super(random);
+ this.v = v;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param v Degrees of freedom
+ * @param random Random generator
+ */
+ public StudentsTDistribution(int v, RandomFactory random) {
+ super(random);
this.v = v;
}
@@ -98,4 +126,36 @@ public class StudentsTDistribution implements Distribution { public String toString() {
return "StudentsTDistribution(v=" + v + ")";
}
+
+ /**
+ * Parameterization class
+ *
+ * @author Erich Schubert
+ *
+ * @apiviz.exclude
+ */
+ public static class Parameterizer extends AbstractDistribution.Parameterizer {
+ /**
+ * Degrees of freedom.
+ */
+ public static final OptionID NU_ID = new OptionID("distribution.studentst.nu", "Degrees of freedom.");
+
+ /** Parameters. */
+ int nu;
+
+ @Override
+ protected void makeOptions(Parameterization config) {
+ super.makeOptions(config);
+
+ IntParameter nuP = new IntParameter(NU_ID);
+ if (config.grab(nuP)) {
+ nu = nuP.intValue();
+ }
+ }
+
+ @Override
+ protected StudentsTDistribution makeInstance() {
+ return new StudentsTDistribution(nu, rnd);
+ }
+ }
}
diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/UniformDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/UniformDistribution.java index efae5080..db2e2fb2 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/UniformDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/UniformDistribution.java @@ -25,12 +25,17 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Uniform distribution. * * @author Erich Schubert */ -public class UniformDistribution implements Distribution { +public class UniformDistribution extends AbstractDistribution { /** * Minimum */ @@ -47,9 +52,30 @@ public class UniformDistribution implements Distribution { private double len; /** - * The random generator. + * Constructor for a uniform distribution on the interval [min, max[ + * + * @param min Minimum value + * @param max Maximum value + * @param random Random generator */ - private Random random; + public UniformDistribution(double min, double max, RandomFactory random) { + super(random); + if (Double.isInfinite(min) || Double.isInfinite(max)) { + throw new ArithmeticException("Infinite values given for uniform distribution."); + } + if (Double.isNaN(min) || Double.isNaN(max)) { + throw new ArithmeticException("NaN values given for uniform distribution."); + } + // Swap parameters if they were given incorrectly. + if (min > max) { + double tmp = min; + min = max; + max = tmp; + } + this.min = min; + this.max = max; + this.len = max - min; + } /** * Constructor for a uniform distribution on the interval [min, max[ @@ -59,7 +85,7 @@ public class UniformDistribution implements Distribution { * @param random Random generator */ public UniformDistribution(double min, double max, Random random) { - super(); + super(random); if (Double.isInfinite(min) || Double.isInfinite(max)) { throw new ArithmeticException("Infinite values given for uniform distribution."); } @@ -75,7 +101,6 @@ public class UniformDistribution implements Distribution { this.min = min; this.max = max; this.len = max - min; - this.random = random; } /** @@ -85,7 +110,7 @@ public class UniformDistribution implements Distribution { * @param max Maximum value */ public UniformDistribution(double min, double max) { - this(min, max, null); + this(min, max, (Random) null); } @Override @@ -135,4 +160,46 @@ public class UniformDistribution implements Distribution { public double getMax() { return max; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** + * Minimum value + */ + public static final OptionID MIN_ID = new OptionID("distribution.min", "Minimum value of distribution."); + + /** + * Maximum value + */ + public static final OptionID MAX_ID = new OptionID("distribution.max", "Maximum value of distribution."); + + /** Parameters. */ + double min, max; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter minP = new DoubleParameter(MIN_ID); + if (config.grab(minP)) { + min = minP.doubleValue(); + } + + DoubleParameter maxP = new DoubleParameter(MAX_ID); + if (config.grab(maxP)) { + max = maxP.doubleValue(); + } + } + + @Override + protected UniformDistribution makeInstance() { + return new UniformDistribution(min, max, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WaldDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WaldDistribution.java index ec0ea712..123ece95 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WaldDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WaldDistribution.java @@ -27,8 +27,11 @@ import java.util.Random; import de.lmu.ifi.dbs.elki.math.MathUtil; import de.lmu.ifi.dbs.elki.utilities.Alias; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; import de.lmu.ifi.dbs.elki.utilities.exceptions.ExceptionMessages; import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; /** * Inverse Gaussian distribution aka Wald distribution @@ -36,9 +39,9 @@ import de.lmu.ifi.dbs.elki.utilities.exceptions.NotImplementedException; * @author Erich Schubert */ @Alias({ "InverseGaussianDistribution", "invgauss" }) -public class WaldDistribution implements Distribution { +public class WaldDistribution extends AbstractDistribution { /** - * Mean value + * Location value */ private double mean; @@ -48,9 +51,17 @@ public class WaldDistribution implements Distribution { private double shape; /** - * The random generator. + * Constructor for wald distribution + * + * @param mean Mean + * @param shape Shape parameter + * @param random Random generator */ - private Random random; + public WaldDistribution(double mean, double shape, Random random) { + super(random); + this.mean = mean; + this.shape = shape; + } /** * Constructor for wald distribution @@ -59,11 +70,10 @@ public class WaldDistribution implements Distribution { * @param shape Shape parameter * @param random Random generator */ - public WaldDistribution(double mean, double shape, Random random) { - super(); + public WaldDistribution(double mean, double shape, RandomFactory random) { + super(random); this.mean = mean; this.shape = shape; - this.random = random; } /** @@ -73,7 +83,7 @@ public class WaldDistribution implements Distribution { * @param shape Shape parameter */ public WaldDistribution(double mean, double shape) { - this(mean, shape, null); + this(mean, shape, (Random) null); } @Override @@ -170,4 +180,36 @@ public class WaldDistribution implements Distribution { // FIXME: implement! throw new NotImplementedException(ExceptionMessages.UNSUPPORTED_NOT_YET); } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double mean, shape; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter meanP = new DoubleParameter(LOCATION_ID); + if (config.grab(meanP)) { + mean = meanP.doubleValue(); + } + + DoubleParameter shapeP = new DoubleParameter(SHAPE_ID); + if (config.grab(shapeP)) { + shape = shapeP.doubleValue(); + } + } + + @Override + protected WaldDistribution makeInstance() { + return new WaldDistribution(mean, shape, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WeibullDistribution.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WeibullDistribution.java index 165f536a..9b7af6d8 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WeibullDistribution.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/WeibullDistribution.java @@ -25,16 +25,20 @@ package de.lmu.ifi.dbs.elki.math.statistics.distribution; import java.util.Random; +import de.lmu.ifi.dbs.elki.utilities.RandomFactory; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; + /** * Weibull distribution. * * @author Erich Schubert */ -public class WeibullDistribution implements Distribution { +public class WeibullDistribution extends AbstractDistribution { /** * Shift offset. */ - double theta = 0.0; + double theta = 0.; /** * Shape parameter k. @@ -47,18 +51,13 @@ public class WeibullDistribution implements Distribution { double lambda; /** - * Random number generator. - */ - Random random; - - /** * Constructor. * * @param k Shape parameter * @param lambda Scale parameter */ public WeibullDistribution(double k, double lambda) { - this(k, lambda, 0.0, null); + this(k, lambda, 0.0, (Random) null); } /** @@ -69,7 +68,7 @@ public class WeibullDistribution implements Distribution { * @param theta Shift offset parameter */ public WeibullDistribution(double k, double lambda, double theta) { - this(k, lambda, theta, null); + this(k, lambda, theta, (Random) null); } /** @@ -80,7 +79,7 @@ public class WeibullDistribution implements Distribution { * @param random Random number generator */ public WeibullDistribution(double k, double lambda, Random random) { - this(k, lambda, 0.0, random); + this(k, lambda, 0., random); } /** @@ -92,11 +91,25 @@ public class WeibullDistribution implements Distribution { * @param random Random number generator */ public WeibullDistribution(double k, double lambda, double theta, Random random) { - super(); + super(random); + this.k = k; + this.lambda = lambda; + this.theta = theta; + } + + /** + * Constructor. + * + * @param k Shape parameter + * @param lambda Scale parameter + * @param theta Shift offset parameter + * @param random Random number generator + */ + public WeibullDistribution(double k, double lambda, double theta, RandomFactory random) { + super(random); this.k = k; this.lambda = lambda; this.theta = theta; - this.random = random; } @Override @@ -179,4 +192,41 @@ public class WeibullDistribution implements Distribution { public String toString() { return "WeibullDistribution(k=" + k + ", lambda=" + lambda + ", theta=" + theta + ")"; } + + /** + * Parameterization class + * + * @author Erich Schubert + * + * @apiviz.exclude + */ + public static class Parameterizer extends AbstractDistribution.Parameterizer { + /** Parameters. */ + double theta, k, lambda; + + @Override + protected void makeOptions(Parameterization config) { + super.makeOptions(config); + + DoubleParameter thetaP = new DoubleParameter(LOCATION_ID, 0.); + if (config.grab(thetaP)) { + theta = thetaP.doubleValue(); + } + + DoubleParameter lambdaP = new DoubleParameter(SCALE_ID); + if (config.grab(lambdaP)) { + lambda = lambdaP.doubleValue(); + } + + DoubleParameter kP = new DoubleParameter(SHAPE_ID); + if (config.grab(kP)) { + k = kP.doubleValue(); + } + } + + @Override + protected WeibullDistribution makeInstance() { + return new WeibullDistribution(theta, k, lambda, rnd); + } + } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/GammaChoiWetteEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/GammaChoiWetteEstimator.java index d41881f0..9e47e81d 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/GammaChoiWetteEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/GammaChoiWetteEstimator.java @@ -72,7 +72,7 @@ public class GammaChoiWetteEstimator implements DistributionEstimator<GammaDistr meanlogx += deltalogx / (i + 1.); } // Initial approximation - final double logmeanx = Math.log(meanx); + final double logmeanx = (meanx > 0) ? Math.log(meanx) : meanlogx; final double diff = logmeanx - meanlogx; double k = (3 - diff + Math.sqrt((diff - 3) * (diff - 3) + 24 * diff)) / (12 * diff); diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceLMMEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceLMMEstimator.java index 1e31af28..4026fdc5 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceLMMEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceLMMEstimator.java @@ -30,7 +30,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; * * @author Erich Schubert * - * @apiviz.has ExponentialDistribution + * @apiviz.has LaplaceDistribution */ public class LaplaceLMMEstimator extends AbstractLMMEstimator<LaplaceDistribution> { /** diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMADEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMADEstimator.java index d4671362..6fe6da0f 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMADEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMADEstimator.java @@ -38,7 +38,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; * * @author Erich Schubert * - * @apiviz.has ExponentialDistribution + * @apiviz.has LaplaceDistribution */ @Reference(title = "Applied Robust Statistics", authors = "D. J. Olive", booktitle = "Applied Robust Statistics", url="http://lagrange.math.siu.edu/Olive/preprints.htm") public class LaplaceMADEstimator extends AbstractMADEstimator<LaplaceDistribution> { diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMLEEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMLEEstimator.java index f44e2b3a..8d2c5707 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMLEEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/LaplaceMLEEstimator.java @@ -42,7 +42,7 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; * * @author Erich Schubert * - * @apiviz.has ExponentialDistribution + * @apiviz.has LaplaceDistribution */ @Reference(title = "The Double Exponential Distribution: Using Calculus to Find a Maximum Likelihood Estimator", authors = "R. M. Norton", booktitle = "The American Statistician 38 (2)", url = "http://dx.doi.org/10.2307%2F2683252") public class LaplaceMLEEstimator implements DistributionEstimator<LaplaceDistribution> { diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/UniformMinMaxEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/UniformMinMaxEstimator.java index e9870884..11bb8231 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/UniformMinMaxEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/UniformMinMaxEstimator.java @@ -74,7 +74,8 @@ public class UniformMinMaxEstimator implements DistributionEstimator<UniformDist /** * Estimate parameters from minimum and maximum observed. * - * @param mm Minimum and Maximum + * @param min Minimum + * @param max Maximum * @return Estimation */ public Distribution estimate(double min, double max) { diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/BestFitEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/BestFitEstimator.java index dee3cbb3..8d57e0b7 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/BestFitEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/BestFitEstimator.java @@ -87,11 +87,11 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; * * @author Erich Schubert * - * @apiviz.composedOf MOMDistributionEstimator - * @apiviz.composedOf MADDistributionEstimator - * @apiviz.composedOf LMMDistributionEstimator - * @apiviz.composedOf LogMOMDistributionEstimator - * @apiviz.composedOf LogMADDistributionEstimator + * @apiviz.uses MOMDistributionEstimator + * @apiviz.uses MADDistributionEstimator + * @apiviz.uses LMMDistributionEstimator + * @apiviz.uses LogMOMDistributionEstimator + * @apiviz.uses LogMADDistributionEstimator */ public class BestFitEstimator implements DistributionEstimator<Distribution> { /** diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/TrimmedEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/TrimmedEstimator.java index 5c1cf448..a78d9760 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/TrimmedEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/TrimmedEstimator.java @@ -31,8 +31,7 @@ import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.ArrayLikeUtil; import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter; import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.LessConstraint; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; @@ -43,6 +42,8 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; * * @author Erich Schubert * + * @apiviz.uses DistributionEstimator + * * @param <D> Distribution type */ public class TrimmedEstimator<D extends Distribution> implements DistributionEstimator<D> { @@ -75,7 +76,7 @@ public class TrimmedEstimator<D extends Distribution> implements DistributionEst final int cut = ((int) (len * trim)) >> 1; // X positions of samples double[] x = new double[len]; - for (int i = 0; i < len; i++) { + for(int i = 0; i < len; i++) { final double val = adapter.getDouble(data, i); x[i] = val; } @@ -136,14 +137,14 @@ public class TrimmedEstimator<D extends Distribution> implements DistributionEst protected void makeOptions(Parameterization config) { super.makeOptions(config); ObjectParameter<DistributionEstimator<D>> innerP = new ObjectParameter<>(INNER_ID, DistributionEstimator.class); - if (config.grab(innerP)) { + if(config.grab(innerP)) { inner = innerP.instantiateClass(config); } DoubleParameter trimP = new DoubleParameter(TRIM_ID); - trimP.addConstraint(new GreaterConstraint(0.)); - trimP.addConstraint(new LessConstraint(0.5)); - if (config.grab(trimP)) { + trimP.addConstraint(CommonConstraints.GREATER_THAN_ZERO_DOUBLE); + trimP.addConstraint(CommonConstraints.LESS_THAN_HALF_DOUBLE); + if(config.grab(trimP)) { trim = trimP.doubleValue(); } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/WinsorisingEstimator.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/WinsorisingEstimator.java index 0ef6318d..47fe427e 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/WinsorisingEstimator.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/WinsorisingEstimator.java @@ -31,8 +31,7 @@ import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter import de.lmu.ifi.dbs.elki.utilities.documentation.Reference; import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer; import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint; -import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.LessConstraint; +import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.CommonConstraints; import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization; import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter; import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; @@ -53,6 +52,8 @@ import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter; * * @author Erich Schubert * + * @apiviz.uses DistributionEstimator + * * @param <D> Distribution type */ @Reference(authors = "C. Hastings, F. Mosteller, J. W. Tukey, C. P. Winsor", title = "Low moments for small samples: a comparative study of order statistics", booktitle = "The Annals of Mathematical Statistics, 18(3)", url = "http://dx.doi.org/10.1214/aoms/1177730388") @@ -86,7 +87,7 @@ public class WinsorisingEstimator<D extends Distribution> implements Distributio final int cut = ((int) (len * winsorize)) >> 1; // X positions of samples double[] x = new double[len]; - for (int i = 0; i < len; i++) { + for(int i = 0; i < len; i++) { final double val = adapter.getDouble(data, i); x[i] = val; } @@ -95,7 +96,7 @@ public class WinsorisingEstimator<D extends Distribution> implements Distributio double max = QuickSelect.quickSelect(x, cut, len, len - 1 - cut); // Winsorize by replacing the smallest and largest values. // QuickSelect ensured that these are correctly in place. - for (int i = 0, j = len - 1; i < cut; i++, j--) { + for(int i = 0, j = len - 1; i < cut; i++, j--) { x[i] = min; x[j] = max; } @@ -146,14 +147,14 @@ public class WinsorisingEstimator<D extends Distribution> implements Distributio protected void makeOptions(Parameterization config) { super.makeOptions(config); ObjectParameter<DistributionEstimator<D>> innerP = new ObjectParameter<>(INNER_ID, DistributionEstimator.class); - if (config.grab(innerP)) { + if(config.grab(innerP)) { inner = innerP.instantiateClass(config); } DoubleParameter trimP = new DoubleParameter(WINSORIZE_ID); - trimP.addConstraint(new GreaterConstraint(0.)); - trimP.addConstraint(new LessConstraint(0.5)); - if (config.grab(trimP)) { + trimP.addConstraint(CommonConstraints.GREATER_THAN_ZERO_DOUBLE); + trimP.addConstraint(CommonConstraints.LESS_THAN_HALF_DOUBLE); + if(config.grab(trimP)) { winsorize = trimP.doubleValue(); } } diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/package-info.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/package-info.java index c4b75f2d..c06be5d7 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/meta/package-info.java @@ -3,4 +3,27 @@ * * @author Erich Schubert */ + +/* + This file is part of ELKI: + Environment for Developing KDD-Applications Supported by Index-Structures + + Copyright (C) 2013 + Ludwig-Maximilians-Universität München + Lehr- und Forschungseinheit für Datenbanksysteme + ELKI Development Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package de.lmu.ifi.dbs.elki.math.statistics.distribution.estimator.meta;
\ No newline at end of file diff --git a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/package-info.java b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/package-info.java index 62c98262..9a9f0993 100644 --- a/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/package-info.java +++ b/src/de/lmu/ifi/dbs/elki/math/statistics/distribution/estimator/package-info.java @@ -2,6 +2,8 @@ * Estimators for statistical distributions. * * @author Erich Schubert + * + * @apiviz.exclude de.lmu.ifi.dbs.elki.math.statistics.distribution.estimator.meta.* */ package de.lmu.ifi.dbs.elki.math.statistics.distribution.estimator; |