use of org.apache.commons.math3.stat.descriptive.summary.Sum in project GDSC-SMLM by aherbert.
the class ApacheLVMFitter method computeFit.
public FitStatus computeFit(double[] y, final double[] y_fit, double[] a, double[] a_dev) {
int n = y.length;
try {
// Different convergence thresholds seem to have no effect on the resulting fit, only the number of
// iterations for convergence
final double initialStepBoundFactor = 100;
final double costRelativeTolerance = 1e-10;
final double parRelativeTolerance = 1e-10;
final double orthoTolerance = 1e-10;
final double threshold = Precision.SAFE_MIN;
// Extract the parameters to be fitted
final double[] initialSolution = getInitialSolution(a);
// TODO - Pass in more advanced stopping criteria.
// Create the target and weight arrays
final double[] yd = new double[n];
final double[] w = new double[n];
for (int i = 0; i < n; i++) {
yd[i] = y[i];
w[i] = 1;
}
LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer(initialStepBoundFactor, costRelativeTolerance, parRelativeTolerance, orthoTolerance, threshold);
//@formatter:off
LeastSquaresBuilder builder = new LeastSquaresBuilder().maxEvaluations(Integer.MAX_VALUE).maxIterations(getMaxEvaluations()).start(initialSolution).target(yd).weight(new DiagonalMatrix(w));
if (f instanceof ExtendedNonLinearFunction && ((ExtendedNonLinearFunction) f).canComputeValuesAndJacobian()) {
// Compute together, or each individually
builder.model(new ValueAndJacobianFunction() {
final ExtendedNonLinearFunction fun = (ExtendedNonLinearFunction) f;
public Pair<RealVector, RealMatrix> value(RealVector point) {
final double[] p = point.toArray();
final Pair<double[], double[][]> result = fun.computeValuesAndJacobian(p);
return new Pair<RealVector, RealMatrix>(new ArrayRealVector(result.getFirst(), false), new Array2DRowRealMatrix(result.getSecond(), false));
}
public RealVector computeValue(double[] params) {
return new ArrayRealVector(fun.computeValues(params), false);
}
public RealMatrix computeJacobian(double[] params) {
return new Array2DRowRealMatrix(fun.computeJacobian(params), false);
}
});
} else {
// Compute separately
builder.model(new MultivariateVectorFunctionWrapper((NonLinearFunction) f, a, n), new MultivariateMatrixFunctionWrapper((NonLinearFunction) f, a, n));
}
LeastSquaresProblem problem = builder.build();
Optimum optimum = optimizer.optimize(problem);
final double[] parameters = optimum.getPoint().toArray();
setSolution(a, parameters);
iterations = optimum.getIterations();
evaluations = optimum.getEvaluations();
if (a_dev != null) {
try {
double[][] covar = optimum.getCovariances(threshold).getData();
setDeviationsFromMatrix(a_dev, covar);
} catch (SingularMatrixException e) {
// Matrix inversion failed. In order to return a solution
// return the reciprocal of the diagonal of the Fisher information
// for a loose bound on the limit
final int[] gradientIndices = f.gradientIndices();
final int nparams = gradientIndices.length;
GradientCalculator calculator = GradientCalculatorFactory.newCalculator(nparams);
double[][] alpha = new double[nparams][nparams];
double[] beta = new double[nparams];
calculator.findLinearised(nparams, y, a, alpha, beta, (NonLinearFunction) f);
FisherInformationMatrix m = new FisherInformationMatrix(alpha);
setDeviations(a_dev, m.crlb(true));
}
}
// Compute function value
if (y_fit != null) {
Gaussian2DFunction f = (Gaussian2DFunction) this.f;
f.initialise0(a);
f.forEach(new ValueProcedure() {
int i = 0;
public void execute(double value) {
y_fit[i] = value;
}
});
}
// As this is unweighted then we can do this to get the sum of squared residuals
// This is the same as optimum.getCost() * optimum.getCost(); The getCost() function
// just computes the dot product anyway.
value = optimum.getResiduals().dotProduct(optimum.getResiduals());
} catch (TooManyEvaluationsException e) {
return FitStatus.TOO_MANY_EVALUATIONS;
} catch (TooManyIterationsException e) {
return FitStatus.TOO_MANY_ITERATIONS;
} catch (ConvergenceException e) {
// Occurs when QR decomposition fails - mark as a singular non-linear model (no solution)
return FitStatus.SINGULAR_NON_LINEAR_MODEL;
} catch (Exception e) {
// TODO - Find out the other exceptions from the fitter and add return values to match.
return FitStatus.UNKNOWN;
}
return FitStatus.OK;
}
use of org.apache.commons.math3.stat.descriptive.summary.Sum in project GDSC-SMLM by aherbert.
the class PoissonGammaGaussianFunction method likelihood.
/**
* Compute the likelihood
*
* @param o
* The observed count
* @param e
* The expected count
* @return The likelihood
*/
public double likelihood(final double o, final double e) {
// Use the same variables as the Python code
final double cij = o;
// convert to photons
final double eta = alpha * e;
if (sigma == 0) {
// No convolution with a Gaussian. Simply evaluate for a Poisson-Gamma distribution.
final double p;
// Any observed count above zero
if (cij > 0.0) {
// The observed count converted to photons
final double nij = alpha * cij;
// The limit on eta * nij is therefore (709/2)^2 = 125670.25
if (eta * nij > 10000) {
// Approximate Bessel function i1(x) when using large x:
// i1(x) ~ exp(x)/sqrt(2*pi*x)
// However the entire equation is logged (creating transform),
// evaluated then raised to e to prevent overflow error on
// large exp(x)
final double transform = 0.5 * Math.log(alpha * eta / cij) - nij - eta + 2 * Math.sqrt(eta * nij) - Math.log(twoSqrtPi * Math.pow(eta * nij, 0.25));
p = FastMath.exp(transform);
} else {
// Second part of equation 135
p = Math.sqrt(alpha * eta / cij) * FastMath.exp(-nij - eta) * Bessel.I1(2 * Math.sqrt(eta * nij));
}
} else if (cij == 0.0) {
p = FastMath.exp(-eta);
} else {
p = 0;
}
return (p > minimumProbability) ? p : minimumProbability;
} else if (useApproximation) {
return mortensenApproximation(cij, eta);
} else {
// This code is the full evaluation of equation 7 from the supplementary information
// of the paper Chao, et al (2013) Nature Methods 10, 335-338.
// It is the full evaluation of a Poisson-Gamma-Gaussian convolution PMF.
// Read noise
final double sk = sigma;
// Gain
final double g = 1.0 / alpha;
// Observed pixel value
final double z = o;
// Expected number of photons
final double vk = eta;
// Compute the integral to infinity of:
// exp( -((z-u)/(sqrt(2)*s)).^2 - u/g ) * sqrt(vk*u/g) .* besseli(1, 2 * sqrt(vk*u/g)) ./ u;
// vk / g
final double vk_g = vk * alpha;
final double sqrt2sigma = Math.sqrt(2) * sk;
// Specify the function to integrate
UnivariateFunction f = new UnivariateFunction() {
public double value(double u) {
return eval(sqrt2sigma, z, vk_g, g, u);
}
};
// Integrate to infinity is not necessary. The convolution of the function with the
// Gaussian should be adequately sampled using a nxSD around the maximum.
// Find a bracket containing the maximum
double lower, upper;
double maxU = Math.max(1, o);
double rLower = maxU;
double rUpper = maxU + 1;
double f1 = f.value(rLower);
double f2 = f.value(rUpper);
// Calculate the simple integral and the range
double sum = f1 + f2;
boolean searchUp = f2 > f1;
if (searchUp) {
while (f2 > f1) {
f1 = f2;
rUpper += 1;
f2 = f.value(rUpper);
sum += f2;
}
maxU = rUpper - 1;
} else {
// Ensure that u stays above zero
while (f1 > f2 && rLower > 1) {
f2 = f1;
rLower -= 1;
f1 = f.value(rLower);
sum += f1;
}
maxU = (rLower > 1) ? rLower + 1 : rLower;
}
lower = Math.max(0, maxU - 5 * sk);
upper = maxU + 5 * sk;
if (useSimpleIntegration && lower > 0) {
// remaining points in the range
for (double u = rLower - 1; u >= lower; u -= 1) {
sum += f.value(u);
}
for (double u = rUpper + 1; u <= upper; u += 1) {
sum += f.value(u);
}
} else {
// Use Legendre-Gauss integrator
try {
final double relativeAccuracy = 1e-4;
final double absoluteAccuracy = 1e-8;
final int minimalIterationCount = 3;
final int maximalIterationCount = 32;
final int integrationPoints = 16;
// Use an integrator that does not use the boundary since u=0 is undefined (divide by zero)
UnivariateIntegrator i = new IterativeLegendreGaussIntegrator(integrationPoints, relativeAccuracy, absoluteAccuracy, minimalIterationCount, maximalIterationCount);
sum = i.integrate(2000, f, lower, upper);
} catch (TooManyEvaluationsException ex) {
return mortensenApproximation(cij, eta);
}
}
// Compute the final probability
//final double
f1 = z / sqrt2sigma;
final double p = (FastMath.exp(-vk) / (sqrt2pi * sk)) * (FastMath.exp(-(f1 * f1)) + sum);
return (p > minimumProbability) ? p : minimumProbability;
}
}
use of org.apache.commons.math3.stat.descriptive.summary.Sum in project lucene-solr by apache.
the class DescribeEvaluator method evaluate.
public Tuple evaluate(Tuple tuple) throws IOException {
if (subEvaluators.size() != 1) {
throw new IOException("describe expects 1 column as a parameters");
}
StreamEvaluator colEval = subEvaluators.get(0);
List<Number> numbers = (List<Number>) colEval.evaluate(tuple);
DescriptiveStatistics descriptiveStatistics = new DescriptiveStatistics();
for (Number n : numbers) {
descriptiveStatistics.addValue(n.doubleValue());
}
Map map = new HashMap();
map.put("max", descriptiveStatistics.getMax());
map.put("mean", descriptiveStatistics.getMean());
map.put("min", descriptiveStatistics.getMin());
map.put("stdev", descriptiveStatistics.getStandardDeviation());
map.put("sum", descriptiveStatistics.getSum());
map.put("N", descriptiveStatistics.getN());
map.put("var", descriptiveStatistics.getVariance());
map.put("kurtosis", descriptiveStatistics.getKurtosis());
map.put("skewness", descriptiveStatistics.getSkewness());
map.put("popVar", descriptiveStatistics.getPopulationVariance());
map.put("geometricMean", descriptiveStatistics.getGeometricMean());
map.put("sumsq", descriptiveStatistics.getSumsq());
return new Tuple(map);
}
use of org.apache.commons.math3.stat.descriptive.summary.Sum in project GDSC-SMLM by aherbert.
the class PCPALMClusters method fitBinomial.
/**
* Fit a zero-truncated Binomial to the cumulative histogram
*
* @param histogramData
* @return
*/
private double[] fitBinomial(HistogramData histogramData) {
// Get the mean and sum of the input histogram
double mean;
double sum = 0;
count = 0;
for (int i = 0; i < histogramData.histogram[1].length; i++) {
count += histogramData.histogram[1][i];
sum += histogramData.histogram[1][i] * i;
}
mean = sum / count;
String name = "Zero-truncated Binomial distribution";
Utils.log("Mean cluster size = %s", Utils.rounded(mean));
Utils.log("Fitting cumulative " + name);
// Convert to a normalised double array for the binomial fitter
double[] histogram = new double[histogramData.histogram[1].length];
for (int i = 0; i < histogramData.histogram[1].length; i++) histogram[i] = histogramData.histogram[1][i] / count;
// Plot the cumulative histogram
String title = TITLE + " Cumulative Distribution";
Plot2 plot = null;
if (showCumulativeHistogram) {
// Create a cumulative histogram for fitting
double[] cumulativeHistogram = new double[histogram.length];
sum = 0;
for (int i = 0; i < histogram.length; i++) {
sum += histogram[i];
cumulativeHistogram[i] = sum;
}
double[] values = Utils.newArray(histogram.length, 0.0, 1.0);
plot = new Plot2(title, "N", "Cumulative Probability", values, cumulativeHistogram);
plot.setLimits(0, histogram.length - 1, 0, 1.05);
plot.addPoints(values, cumulativeHistogram, Plot2.CIRCLE);
Utils.display(title, plot);
}
// Do fitting for different N
double bestSS = Double.POSITIVE_INFINITY;
double[] parameters = null;
int worse = 0;
int N = histogram.length - 1;
int min = minN;
final boolean customRange = (minN > 1) || (maxN > 0);
if (min > N)
min = N;
if (maxN > 0 && N > maxN)
N = maxN;
Utils.log("Fitting N from %d to %d%s", min, N, (customRange) ? " (custom-range)" : "");
// Since varying the N should be done in integer steps do this
// for n=1,2,3,... until the SS peaks then falls off (is worse then the best
// score several times in succession)
BinomialFitter bf = new BinomialFitter(new IJLogger());
bf.setMaximumLikelihood(maximumLikelihood);
for (int n = min; n <= N; n++) {
PointValuePair solution = bf.fitBinomial(histogram, mean, n, true);
if (solution == null)
continue;
double p = solution.getPointRef()[0];
Utils.log("Fitted %s : N=%d, p=%s. SS=%g", name, n, Utils.rounded(p), solution.getValue());
if (bestSS > solution.getValue()) {
bestSS = solution.getValue();
parameters = new double[] { n, p };
worse = 0;
} else if (bestSS < Double.POSITIVE_INFINITY) {
if (++worse >= 3)
break;
}
if (showCumulativeHistogram)
addToPlot(n, p, title, plot, new Color((float) n / N, 0, 1f - (float) n / N));
}
// Add best it in magenta
if (showCumulativeHistogram && parameters != null)
addToPlot((int) parameters[0], parameters[1], title, plot, Color.magenta);
return parameters;
}
use of org.apache.commons.math3.stat.descriptive.summary.Sum in project webofneeds by researchstudio-sat.
the class Kneedle method detectKneeOrElbowPoints.
/**
* Detect all knee points in a curve according to "Kneedle" algorithm.
* Alternatively this method can detect elbow points instead of knee points.
*
* @param x x-coordintes of curve, must be increasing in value
* @param y y-coordinates of curve
* @param detectElbows if true detects elbow points, if false detects knee points
* @return array of indices of knee (or elbow) points in the curve
*/
private int[] detectKneeOrElbowPoints(final double[] x, final double[] y, boolean detectElbows) {
checkConstraints(x, y);
List<Integer> kneeIndices = new LinkedList<Integer>();
List<Integer> lmxIndices = new LinkedList<Integer>();
List<Double> lmxThresholds = new LinkedList<Double>();
double[] xn = normalize(x);
double[] yn = normalize(y);
// compute the y difference values
double[] yDiff = new double[y.length];
for (int i = 0; i < y.length; i++) {
yDiff[i] = yn[i] - xn[i];
}
// original yDiff curve
if (detectElbows) {
DescriptiveStatistics stats = new DescriptiveStatistics(yDiff);
for (int i = 0; i < yDiff.length; i++) {
yDiff[i] = stats.getMax() - yDiff[i];
}
}
// find local maxima, compute threshold values and detect knee points
boolean detectKneeForLastLmx = false;
for (int i = 1; i < y.length - 1; i++) {
// than for its left and right neighbour => local maximum
if (yDiff[i] > yDiff[i - 1] && yDiff[i] > yDiff[i + 1]) {
// local maximum found
lmxIndices.add(i);
// compute the threshold value for this local maximum
// NOTE: As stated in the paper the threshold Tlmx is computed. Since the mean distance of all consecutive
// x-values summed together for a normalized function is always (1 / (n -1)) we do not have to compute the
// whole sum here as stated in the paper.
double tlmx = yDiff[i] - sensitivity / (xn.length - 1);
lmxThresholds.add(tlmx);
// try to find out if the current local maximum is a knee point
detectKneeForLastLmx = true;
}
// check for new knee point
if (detectKneeForLastLmx) {
if (yDiff[i + 1] < lmxThresholds.get(lmxThresholds.size() - 1)) {
// knee detected
kneeIndices.add(lmxIndices.get(lmxIndices.size() - 1));
detectKneeForLastLmx = false;
}
}
}
int[] knees = new int[kneeIndices.size()];
for (int i = 0; i < kneeIndices.size(); i++) {
knees[i] = kneeIndices.get(i);
}
return knees;
}
Aggregations