package gdsc.smlm.fitting.nonlinear.gradient; import java.util.ArrayList; import org.apache.commons.math3.distribution.PoissonDistribution; import org.apache.commons.math3.random.RandomDataGenerator; import org.apache.commons.math3.random.Well19937c; import org.junit.Assert; import org.junit.Test; import gdsc.core.ij.Utils; import gdsc.core.utils.DoubleEquality; import gdsc.core.utils.Statistics; import gdsc.smlm.TestSettings; import gdsc.smlm.fitting.linear.EJMLLinearSolver; import gdsc.smlm.function.CameraNoiseModel; import gdsc.smlm.function.NonLinearFunction; import gdsc.smlm.function.PoissonCalculator; import gdsc.smlm.function.gaussian.EllipticalGaussian2DFunction; import gdsc.smlm.function.gaussian.Gaussian2DFunction; import gdsc.smlm.function.gaussian.SingleCircularGaussian2DFunction; import gdsc.smlm.function.gaussian.SingleEllipticalGaussian2DFunction; import gdsc.smlm.function.gaussian.SingleFixedGaussian2DFunction; import gdsc.smlm.function.gaussian.SingleFreeCircularGaussian2DFunction; import gdsc.smlm.function.gaussian.SingleNBFixedGaussian2DFunction; /** * Contains speed tests for the fastest method for calculating the Hessian and gradient vector * for use in NonLinearFit */ public class GradientCalculatorSpeedTest { boolean speedTests = false; DoubleEquality eq = new DoubleEquality(6, 1e-16); int MAX_ITER = 20000; int blockWidth = 10; double Background = 0.5; double Amplitude = 100; double Angle = Math.PI; double Xpos = 5; double Ypos = 5; double Xwidth = 1.2; double Ywidth = 1.2; RandomDataGenerator rdg; @Test public void gradientCalculatorFactoryCreatesOptimisedCalculators() { Assert.assertEquals(GradientCalculatorFactory.newCalculator(3).getClass(), GradientCalculator3.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(4).getClass(), GradientCalculator4.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(5).getClass(), GradientCalculator5.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(6).getClass(), GradientCalculator6.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(7).getClass(), GradientCalculator7.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(13).getClass(), GradientCalculator.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(3, true).getClass(), MLEGradientCalculator3.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(4, true).getClass(), MLEGradientCalculator4.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(5, true).getClass(), MLEGradientCalculator5.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(6, true).getClass(), MLEGradientCalculator6.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(7, true).getClass(), MLEGradientCalculator7.class); Assert.assertEquals(GradientCalculatorFactory.newCalculator(13, true).getClass(), MLEGradientCalculator.class); } @Test public void mleGradientCalculator7ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator( new SingleEllipticalGaussian2DFunction(blockWidth, blockWidth), 7, true); } @Test public void mleGradientCalculator7IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator( new SingleEllipticalGaussian2DFunction(blockWidth, blockWidth), 7, true); } @Test public void mleGradientCalculator6ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator( new SingleFreeCircularGaussian2DFunction(blockWidth, blockWidth), 6, true); } @Test public void mleGradientCalculator6IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator( new SingleFreeCircularGaussian2DFunction(blockWidth, blockWidth), 6, true); } @Test public void mleGradientCalculator5ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator( new SingleCircularGaussian2DFunction(blockWidth, blockWidth), 5, true); } @Test public void mleGradientCalculator5IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator(new SingleCircularGaussian2DFunction(blockWidth, blockWidth), 5, true); } @Test public void mleGradientCalculator4ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator(new SingleFixedGaussian2DFunction(blockWidth, blockWidth), 4, true); } @Test public void mleGradientCalculator4IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator(new SingleFixedGaussian2DFunction(blockWidth, blockWidth), 4, true); } @Test public void mleGradientCalculator3ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator(new SingleNBFixedGaussian2DFunction(blockWidth, blockWidth), 3, true); } @Test public void mleGradientCalculator3IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator(new SingleNBFixedGaussian2DFunction(blockWidth, blockWidth), 3, true); } @Test public void gradientCalculator7ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator( new SingleEllipticalGaussian2DFunction(blockWidth, blockWidth), 7, false); } @Test public void gradientCalculator7IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator( new SingleEllipticalGaussian2DFunction(blockWidth, blockWidth), 7, false); } @Test public void gradientCalculator6ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator( new SingleFreeCircularGaussian2DFunction(blockWidth, blockWidth), 6, false); } @Test public void gradientCalculator6IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator( new SingleFreeCircularGaussian2DFunction(blockWidth, blockWidth), 6, false); } @Test public void gradientCalculator5ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator( new SingleCircularGaussian2DFunction(blockWidth, blockWidth), 5, false); } @Test public void gradientCalculator5IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator(new SingleCircularGaussian2DFunction(blockWidth, blockWidth), 5, false); } @Test public void gradientCalculator4ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator(new SingleFixedGaussian2DFunction(blockWidth, blockWidth), 4, false); } @Test public void gradientCalculator4IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator(new SingleFixedGaussian2DFunction(blockWidth, blockWidth), 4, false); } @Test public void gradientCalculator3ComputesSameAsGradientCalculator() { gradientCalculatorNComputesSameAsGradientCalculator(new SingleNBFixedGaussian2DFunction(blockWidth, blockWidth), 3, false); } @Test public void gradientCalculator3IsFasterThanGradientCalculator() { gradientCalculatorNIsFasterThanGradientCalculator(new SingleNBFixedGaussian2DFunction(blockWidth, blockWidth), 3, false); } private void gradientCalculatorNComputesSameAsGradientCalculator(Gaussian2DFunction func, int nparams, boolean mle) { // Check the function is the correct size Assert.assertEquals(nparams, func.gradientIndices().length); int iter = 100; rdg = new RandomDataGenerator(new Well19937c(30051977)); double[][] alpha = new double[nparams][nparams]; double[] beta = new double[nparams]; double[][] alpha2 = new double[nparams][nparams]; double[] beta2 = new double[nparams]; ArrayList<double[]> paramsList = new ArrayList<double[]>(iter); ArrayList<double[]> yList = new ArrayList<double[]>(iter); int[] x = createData(1, iter, paramsList, yList); GradientCalculator calc = (mle) ? new MLEGradientCalculator(beta.length) : new GradientCalculator(beta.length); GradientCalculator calc2 = GradientCalculatorFactory.newCalculator(nparams, mle); for (int i = 0; i < paramsList.size(); i++) { double s = calc.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); double s2 = calc2.findLinearised(x, yList.get(i), paramsList.get(i), alpha2, beta2, func); Assert.assertTrue("Result: Not same @ " + i, eq.almostEqualComplement(s, s2)); Assert.assertTrue("Observations: Not same beta @ " + i, eq.almostEqualComplement(beta, beta2)); for (int j = 0; j < beta.length; j++) Assert.assertTrue("Observations: Not same alpha @ " + i, eq.almostEqualComplement(alpha[j], alpha2[j])); } for (int i = 0; i < paramsList.size(); i++) { double s = calc.findLinearised(x.length, yList.get(i), paramsList.get(i), alpha, beta, func); double s2 = calc2.findLinearised(x.length, yList.get(i), paramsList.get(i), alpha2, beta2, func); Assert.assertTrue("N-Result: Not same @ " + i, eq.almostEqualComplement(s, s2)); Assert.assertTrue("N-observations: Not same beta @ " + i, eq.almostEqualComplement(beta, beta2)); for (int j = 0; j < beta.length; j++) Assert.assertTrue("N-observations: Not same alpha @ " + i, eq.almostEqualComplement(alpha[j], alpha2[j])); } if (!mle) { func.setNoiseModel(CameraNoiseModel.createNoiseModel(10, 0, true)); for (int i = 0; i < paramsList.size(); i++) { double s = calc.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); double s2 = calc2.findLinearised(x, yList.get(i), paramsList.get(i), alpha2, beta2, func); Assert.assertTrue("Result+Noise: Not same @ " + i, eq.almostEqualComplement(s, s2)); Assert.assertTrue("Observations+Noise: Not same beta @ " + i, eq.almostEqualComplement(beta, beta2)); for (int j = 0; j < beta.length; j++) Assert.assertTrue("Observations+Noise: Not same alpha @ " + i, eq.almostEqualComplement(alpha[j], alpha2[j])); } for (int i = 0; i < paramsList.size(); i++) { double s = calc.findLinearised(x.length, yList.get(i), paramsList.get(i), alpha, beta, func); double s2 = calc2.findLinearised(x.length, yList.get(i), paramsList.get(i), alpha2, beta2, func); Assert.assertTrue("N-Result+Noise: Not same @ " + i, eq.almostEqualComplement(s, s2)); Assert.assertTrue("N-Observations+Noise: Not same beta @ " + i, eq.almostEqualComplement(beta, beta2)); for (int j = 0; j < beta.length; j++) Assert.assertTrue("N-Observations+Noise: Not same alpha @ " + i, eq.almostEqualComplement(alpha[j], alpha2[j])); } } // Only the diagonal Fisher Information has been unrolled into the other calculators for (int i = 0; i < paramsList.size(); i++) { beta = calc.fisherInformationDiagonal(x.length, paramsList.get(i), func); beta2 = calc.fisherInformationDiagonal(x.length, paramsList.get(i), func); Assert.assertTrue("Not same diagonal @ " + i, eq.almostEqualComplement(beta, beta2)); } } private void gradientCalculatorNIsFasterThanGradientCalculator(Gaussian2DFunction func, int nparams, boolean mle) { org.junit.Assume.assumeTrue(speedTests || TestSettings.RUN_SPEED_TESTS); // Check the function is the correct size Assert.assertEquals(nparams, func.gradientIndices().length); int iter = 10000; rdg = new RandomDataGenerator(new Well19937c(30051977)); double[][] alpha = new double[nparams][nparams]; double[] beta = new double[nparams]; ArrayList<double[]> paramsList = new ArrayList<double[]>(iter); ArrayList<double[]> yList = new ArrayList<double[]>(iter); int[] x = createData(1, iter, paramsList, yList); GradientCalculator calc = (mle) ? new MLEGradientCalculator(beta.length) : new GradientCalculator(beta.length); GradientCalculator calc2 = GradientCalculatorFactory.newCalculator(nparams, mle); for (int i = 0; i < paramsList.size(); i++) calc.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); for (int i = 0; i < paramsList.size(); i++) calc2.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); long start1 = System.nanoTime(); for (int i = 0; i < paramsList.size(); i++) calc.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); start1 = System.nanoTime() - start1; long start2 = System.nanoTime(); for (int i = 0; i < paramsList.size(); i++) calc2.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); start2 = System.nanoTime() - start2; log("%sLinearised GradientCalculator = %d : GradientCalculator%d = %d : %fx\n", (mle) ? "MLE " : "", start1, nparams, start2, (1.0 * start1) / start2); if (TestSettings.ASSERT_SPEED_TESTS) Assert.assertTrue(start2 < start1); for (int i = 0; i < paramsList.size(); i++) calc.fisherInformationDiagonal(x.length, paramsList.get(i), func); for (int i = 0; i < paramsList.size(); i++) calc2.fisherInformationDiagonal(x.length, paramsList.get(i), func); start1 = System.nanoTime(); for (int i = 0; i < paramsList.size(); i++) calc.fisherInformationDiagonal(x.length, paramsList.get(i), func); start1 = System.nanoTime() - start1; start2 = System.nanoTime(); for (int i = 0; i < paramsList.size(); i++) calc2.fisherInformationDiagonal(x.length, paramsList.get(i), func); start2 = System.nanoTime() - start2; log("%sFisher Diagonal GradientCalculator = %d : GradientCalculator%d = %d : %fx\n", (mle) ? "MLE " : "", start1, nparams, start2, (1.0 * start1) / start2); if (TestSettings.ASSERT_SPEED_TESTS) Assert.assertTrue(start2 < start1); } @Test public void gradientCalculatorAssumedXIsFasterThanGradientCalculator() { org.junit.Assume.assumeTrue(speedTests || TestSettings.RUN_SPEED_TESTS); int iter = 10000; rdg = new RandomDataGenerator(new Well19937c(30051977)); double[][] alpha = new double[7][7]; double[] beta = new double[7]; ArrayList<double[]> paramsList = new ArrayList<double[]>(iter); ArrayList<double[]> yList = new ArrayList<double[]>(iter); int[] x = createData(1, iter, paramsList, yList); GradientCalculator calc = new GradientCalculator6(); GradientCalculator calc2 = new GradientCalculator6(); SingleFreeCircularGaussian2DFunction func = new SingleFreeCircularGaussian2DFunction(blockWidth, blockWidth); int n = x.length; for (int i = 0; i < paramsList.size(); i++) calc.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); for (int i = 0; i < paramsList.size(); i++) calc2.findLinearised(n, yList.get(i), paramsList.get(i), alpha, beta, func); long start1 = System.nanoTime(); for (int i = 0; i < paramsList.size(); i++) calc.findLinearised(x, yList.get(i), paramsList.get(i), alpha, beta, func); start1 = System.nanoTime() - start1; long start2 = System.nanoTime(); for (int i = 0; i < paramsList.size(); i++) calc2.findLinearised(n, yList.get(i), paramsList.get(i), alpha, beta, func); start2 = System.nanoTime() - start2; log("GradientCalculator = %d : GradientCalculatorAssumed = %d : %fx\n", start1, start2, (1.0 * start1) / start2); if (TestSettings.ASSERT_SPEED_TESTS) Assert.assertTrue(start2 < start1); } @Test public void gradientCalculatorComputesGradient() { gradientCalculatorComputesGradient(new GradientCalculator(7)); } @Test public void mleGradientCalculatorComputesGradient() { gradientCalculatorComputesGradient(new MLEGradientCalculator(7)); } private void gradientCalculatorComputesGradient(GradientCalculator calc) { int nparams = calc.nparams; Gaussian2DFunction func = new SingleEllipticalGaussian2DFunction(blockWidth, blockWidth); // Check the function is the correct size Assert.assertEquals(nparams, func.gradientIndices().length); int iter = 100; rdg = new RandomDataGenerator(new Well19937c(30051977)); double[] beta = new double[nparams]; double[] beta2 = new double[nparams]; ArrayList<double[]> paramsList = new ArrayList<double[]>(iter); ArrayList<double[]> yList = new ArrayList<double[]>(iter); int[] x = createData(1, iter, paramsList, yList, true); double delta = 1e-3; DoubleEquality eq = new DoubleEquality(3, 1e-3); for (int i = 0; i < paramsList.size(); i++) { double[] y = yList.get(i); double[] a = paramsList.get(i); double[] a2 = a.clone(); //double s = calc.evaluate(x, y, a, beta, func); for (int j = 0; j < nparams; j++) { double d = (a[j] == 0) ? 1e-3 : a[j] * delta; a2[j] = a[j] + d; double s1 = calc.evaluate(x, y, a2, beta2, func); a2[j] = a[j] - d; double s2 = calc.evaluate(x, y, a2, beta2, func); a2[j] = a[j]; double gradient = (s1 - s2) / (2 * d); //System.out.printf("[%d,%d] %f (%s %f+/-%f) %f ?= %f\n", i, j, s, func.getName(j), a[j], d, beta[j], // gradient); Assert.assertTrue("Not same gradient @ " + j, eq.almostEqualComplement(beta[j], gradient)); } } } @Test public void mleGradientCalculatorComputesLikelihood() { //@formatter:off NonLinearFunction func = new NonLinearFunction(){ double u; public void initialise(double[] a) { u = a[0]; } public int[] gradientIndices() { return null; } public double eval(int x, double[] dyda) { return 0; } public double eval(int x) { return u; } public double eval(int x, double[] dyda, double[] w) { return 0; } public double evalw(int x, double[] w) { return 0; } public boolean canComputeWeights() { return false; } public int getNumberOfGradients() { return 0; } }; //@formatter:on int[] xx = Utils.newArray(100, 0, 1); double[] xxx = Utils.newArray(100, 0, 1.0); for (double u : new double[] { 0.79, 2.5, 5.32 }) { double ll = 0; PoissonDistribution pd = new PoissonDistribution(u); for (int x : xx) { double o = MLEGradientCalculator.likelihood(u, x); double e = pd.probability(x); Assert.assertEquals("likelihood", e, o, e * 1e-10); o = MLEGradientCalculator.logLikelihood(u, x); e = pd.logProbability(x); Assert.assertEquals("log likelihood", e, o, Math.abs(e) * 1e-10); ll += e; } MLEGradientCalculator gc = new MLEGradientCalculator(1); double o = gc.logLikelihood(xxx, new double[] { u }, func); Assert.assertEquals("sum log likelihood", ll, o, Math.abs(ll) * 1e-10); } } @Test public void gradientCalculatorComputesSameOutputWithBias() { Gaussian2DFunction func = new SingleEllipticalGaussian2DFunction(blockWidth, blockWidth); int nparams = func.getNumberOfGradients(); GradientCalculator calc = new GradientCalculator(nparams); int n = func.size(); int iter = 100; rdg = new RandomDataGenerator(new Well19937c(30051977)); ArrayList<double[]> paramsList = new ArrayList<double[]>(iter); ArrayList<double[]> yList = new ArrayList<double[]>(iter); ArrayList<double[][]> alphaList = new ArrayList<double[][]>(iter); ArrayList<double[]> betaList = new ArrayList<double[]>(iter); ArrayList<double[]> xList = new ArrayList<double[]>(iter); // Manipulate the background double defaultBackground = Background; try { Background = 1e-2; createData(1, iter, paramsList, yList, true); EJMLLinearSolver solver = new EJMLLinearSolver(5, 1e-6); for (int i = 0; i < paramsList.size(); i++) { double[] y = yList.get(i); double[] a = paramsList.get(i); double[][] alpha = new double[nparams][nparams]; double[] beta = new double[nparams]; calc.findLinearised(n, y, a, alpha, beta, func); alphaList.add(alpha); betaList.add(beta.clone()); for (int j = 0; j < nparams; j++) { if (Math.abs(beta[j]) < 1e-6) System.out.printf("[%d] Tiny beta %s %g\n", i, func.getName(j), beta[j]); } // Solve if (!solver.solve(alpha, beta)) throw new AssertionError(); xList.add(beta); //System.out.println(Arrays.toString(beta)); } double[][] alpha = new double[nparams][nparams]; double[] beta = new double[nparams]; //for (int b = 1; b < 1000; b *= 2) for (double b : new double[] { -500, -100, -10, -1, -0.1, 0, 0.1, 1, 10, 100, 500 }) { Statistics[] rel = new Statistics[nparams]; Statistics[] abs = new Statistics[nparams]; for (int i = 0; i < nparams; i++) { rel[i] = new Statistics(); abs[i] = new Statistics(); } for (int i = 0; i < paramsList.size(); i++) { double[] y = add(yList.get(i), b); double[] a = paramsList.get(i).clone(); a[0] += b; calc.findLinearised(n, y, a, alpha, beta, func); double[][] alpha2 = alphaList.get(i); double[] beta2 = betaList.get(i); double[] x2 = xList.get(i); Assert.assertArrayEquals("Beta", beta2, beta, 1e-10); for (int j = 0; j < nparams; j++) { Assert.assertArrayEquals("Alpha", alpha2[j], alpha[j], 1e-10); } // Solve solver.solve(alpha, beta); Assert.assertArrayEquals("X", x2, beta, 1e-10); for (int j = 0; j < nparams; j++) { rel[j].add(DoubleEquality.relativeError(x2[j], beta[j])); abs[j].add(Math.abs(x2[j] - beta[j])); } } for (int i = 0; i < nparams; i++) System.out.printf("Bias = %.2f : %s : Rel %g +/- %g: Abs %g +/- %g\n", b, func.getName(i), rel[i].getMean(), rel[i].getStandardDeviation(), abs[i].getMean(), abs[i].getStandardDeviation()); } } finally { Background = defaultBackground; } } private double[] add(double[] d, double b) { d = d.clone(); for (int i = 0; i < d.length; i++) d[i] += b; return d; } @Test public void mleCalculatorComputesLogLikelihoodRatio() { EllipticalGaussian2DFunction func = new EllipticalGaussian2DFunction(1, blockWidth, blockWidth); int n = blockWidth * blockWidth; double[] a = new double[7]; rdg = new RandomDataGenerator(new Well19937c(30051977)); for (int run = 5; run-- > 0;) { a[0] = random(Background); a[1] = random(Amplitude); a[2] = random(Angle); a[3] = random(Xpos); a[4] = random(Ypos); a[5] = random(Xwidth); a[6] = random(Ywidth); // Simulate Poisson process func.initialise(a); double[] x = Utils.newArray(n, 0, 1.0); double[] u = new double[x.length]; for (int i = 0; i < n; i++) { u[i] = func.eval(i); if (u[i] > 0) x[i] = rdg.nextPoisson(u[i]); } GradientCalculator calc = GradientCalculatorFactory.newCalculator(func.getNumberOfGradients(), true); double[][] alpha = new double[7][7]; double[] beta = new double[7]; double llr = PoissonCalculator.logLikelihoodRatio(u, x); double llr2 = calc.findLinearised(n, x, a, alpha, beta, func); //System.out.printf("llr=%f, llr2=%f\n", llr, llr2); Assert.assertEquals("Log-likelihood ratio", llr, llr2, llr * 1e-10); } } /** * Create random elliptical Gaussian data an returns the data plus an estimate of the parameters. * Only the chosen parameters are randomised and returned for a maximum of (background, amplitude, angle, xpos, * ypos, xwidth, ywidth } * * @param npeaks * the npeaks * @param params * set on output * @param randomiseParams * Set to true to randomise the params * @return the double[] */ private double[] doubleCreateGaussianData(int npeaks, double[] params, boolean randomiseParams) { int n = blockWidth * blockWidth; // Generate a 2D Gaussian EllipticalGaussian2DFunction func = new EllipticalGaussian2DFunction(npeaks, blockWidth, blockWidth); params[0] = random(Background); for (int i = 0, j = 1; i < npeaks; i++, j += 6) { params[j] = random(Amplitude); params[j + 1] = random(Angle); params[j + 2] = random(Xpos); params[j + 3] = random(Ypos); params[j + 4] = random(Xwidth); params[j + 5] = random(Ywidth); } double[] dy_da = new double[params.length]; double[] y = new double[n]; func.initialise(params); for (int i = 0; i < y.length; i++) { // Add random Poisson noise y[i] = rdg.nextPoisson(func.eval(i, dy_da)); } if (randomiseParams) { params[0] = random(params[0]); for (int i = 0, j = 1; i < npeaks; i++, j += 6) { params[j] = random(params[j]); params[j + 1] = random(params[j + 1]); params[j + 2] = random(params[j + 2]); params[j + 3] = random(params[j + 3]); params[j + 4] = random(params[j + 4]); params[j + 5] = random(params[j + 5]); //params[j + 4]; } } return y; } private double random(double d) { return d + rdg.nextUniform(-d * 0.1, d * 0.1); } protected int[] createData(int npeaks, int iter, ArrayList<double[]> paramsList, ArrayList<double[]> yList) { return createData(npeaks, iter, paramsList, yList, true); } protected int[] createData(int npeaks, int iter, ArrayList<double[]> paramsList, ArrayList<double[]> yList, boolean randomiseParams) { int[] x = new int[blockWidth * blockWidth]; for (int i = 0; i < x.length; i++) x[i] = i; for (int i = 0; i < iter; i++) { double[] params = new double[1 + 6 * npeaks]; double[] y = doubleCreateGaussianData(npeaks, params, randomiseParams); paramsList.add(params); yList.add(y); } return x; } protected ArrayList<double[]> copyList(ArrayList<double[]> paramsList) { ArrayList<double[]> params2List = new ArrayList<double[]>(paramsList.size()); for (int i = 0; i < paramsList.size(); i++) { params2List.add(copydouble(paramsList.get(i))); } return params2List; } private double[] copydouble(double[] d) { double[] d2 = new double[d.length]; for (int i = 0; i < d.length; i++) d2[i] = d[i]; return d2; } void log(String format, Object... args) { System.out.printf(format, args); } }