23 public static final int STRAIGHT_LINE=0,POLY2=1,POLY3=2,POLY4=3,
24 EXPONENTIAL=4,POWER=5,LOG=6,RODBARD=7,GAMMA_VARIATE=8, LOG2=9;
26 public static final int IterFactor = 500;
28 public static final String[] fitList = {
"Straight Line",
"2nd Degree Polynomial",
29 "3rd Degree Polynomial",
"4th Degree Polynomial",
"Exponential",
"Power",
30 "log",
"Rodbard",
"Gamma Variate",
"y = a+b*ln(x-c)"};
32 public static final String[] fList = {
"y = a+bx",
"y = a+bx+cx^2",
33 "y = a+bx+cx^2+dx^3",
"y = a+bx+cx^2+dx^3+ex^4",
"y = a*exp(bx)",
"y = ax^b",
34 "y = a*ln(bx)",
"y = d+(a-d)/(1+(x/c)^b)",
"y = a*(x-b)^c*exp(-(x-b)/d)",
"y = a+b*ln(x-c)"};
36 private static final double alpha = -1.0;
37 private static final double beta = 0.5;
38 private static final double gamma = 2.0;
39 private static final double root2 = 1.414214;
42 private double[] xData, yData;
43 private int numPoints;
44 private int numParams;
45 private int numVertices;
47 private int nextWorst;
49 private double[][] simp;
50 private double[] next;
54 private double maxError;
60 numPoints = xData.length;
70 public void doFit(
int fitType) {
71 doFit(fitType,
false);
74 public void doFit(
int fitType,
boolean showSettings) {
75 if (fitType < STRAIGHT_LINE || fitType > LOG2)
76 throw new IllegalArgumentException(
"Invalid fit type");
79 if (showSettings) settingsDialog();
84 double[] center =
new double[numParams];
87 for (
int i = 0; i < numParams; i++) center[i] = 0.0;
89 for (
int i = 0; i < numVertices; i++)
91 for (
int j = 0; j < numParams; j++)
92 center[j] += simp[i][j];
94 for (
int i = 0; i < numParams; i++) {
95 center[i] /= numParams;
96 next[i] = center[i] + alpha*(simp[worst][i] - center[i]);
100 if (next[numParams] <= simp[best][numParams]) {
103 for (
int i = 0; i < numParams; i++)
104 next[i] = center[i] + gamma * (simp[worst][i] - center[i]);
107 if (next[numParams] <= simp[worst][numParams])
111 else if (next[numParams] <= simp[nextWorst][numParams]) {
116 for (
int i = 0; i < numParams; i++)
117 next[i] = center[i] + beta*(simp[worst][i] - center[i]);
120 if (next[numParams] <= simp[nextWorst][numParams]) {
125 for (
int i = 0; i < numVertices; i++) {
127 for (
int j = 0; j < numVertices; j++)
128 simp[i][j] = beta*(simp[i][j]+simp[best][j]);
129 sumResiduals(simp[i]);
136 double rtol = 2 * Math.abs(simp[best][numParams] - simp[worst][numParams]) /
137 (Math.abs(simp[best][numParams]) + Math.abs(simp[worst][numParams]) + 0.0000000001);
139 if (numIter >= maxIter) done =
true;
140 else if (rtol < maxError) {
158 numVertices = numParams + 1;
159 simp =
new double[numVertices][numVertices];
160 next =
new double[numVertices];
162 double firstx = xData[0];
163 double firsty = yData[0];
164 double lastx = xData[numPoints-1];
165 double lasty = yData[numPoints-1];
166 double xmean = (firstx+lastx)/2.0;
167 double ymean = (firsty+lasty)/2.0;
169 if ((lastx - firstx) != 0.0)
170 slope = (lasty - firsty)/(lastx - firstx);
173 double yintercept = firsty - slope * firstx;
174 maxIter = IterFactor * numParams * numParams;
179 simp[0][0] = yintercept;
183 simp[0][0] = yintercept;
188 simp[0][0] = yintercept;
194 simp[0][0] = yintercept;
225 double ab = xData[
getMax(yData)] - firstx;
226 simp[0][2] = Math.sqrt(ab);
227 simp[0][3] = Math.sqrt(ab);
228 simp[0][1] = yData[
getMax(yData)] / (Math.pow(ab, simp[0][2]) * Math.exp(-ab/simp[0][3]));
239 private void settingsDialog() {
240 GenericDialog gd =
new GenericDialog(
"Simplex Fitting Options", IJ.getInstance());
241 gd.addMessage(
"Function name: " + fitList[fit] +
"\n" +
242 "Formula: " + fList[fit]);
244 for (
int i = 0; i < numParams; i++) {
245 gd.addNumericField(
"Initial "+(
new Character(pChar)).toString()+
":", simp[0][i], 2);
248 gd.addNumericField(
"Maximum iterations:", maxIter, 0);
249 gd.addNumericField(
"Number of restarts:", restarts, 0);
250 gd.addNumericField(
"Error tolerance [1*10^(-x)]:", -(Math.log(maxError)/Math.log(10)), 0);
252 if (gd.wasCanceled() || gd.invalidNumber()) {
253 IJ.error(
"Parameter setting canceled.\nUsing default parameters.");
256 for (
int i = 0; i < numParams; i++) {
257 simp[0][i] = gd.getNextNumber();
259 maxIter = (int) gd.getNextNumber();
260 restarts = (int) gd.getNextNumber();
261 maxError = Math.pow(10.0, -gd.getNextNumber());
265 void restart(
int n) {
267 for (
int i = 0; i < numParams; i++) {
268 simp[0][i] = simp[n][i];
270 sumResiduals(simp[0]);
271 double[] step =
new double[numParams];
272 for (
int i = 0; i < numParams; i++) {
273 step[i] = simp[0][i] / 2.0;
278 double[] p =
new double[numParams];
279 double[] q =
new double[numParams];
280 for (
int i = 0; i < numParams; i++) {
281 p[i] = step[i] * (Math.sqrt(numVertices) + numParams - 1.0)/(numParams * root2);
282 q[i] = step[i] * (Math.sqrt(numVertices) - 1.0)/(numParams * root2);
285 for (
int i = 1; i < numVertices; i++) {
286 for (
int j = 0; j < numParams; j++) {
287 simp[i][j] = simp[i-1][j] + q[j];
289 simp[i][i-1] = simp[i][i-1] + p[i-1];
290 sumResiduals(simp[i]);
300 void showSimplex(
int iter) {
301 ij.IJ.write(
"" + iter);
302 for (
int i = 0; i < numVertices; i++) {
304 for (
int j=0; j < numVertices; j++)
305 s +=
" "+ ij.IJ.d2s(simp[i][j], 6);
313 case STRAIGHT_LINE:
return 2;
314 case POLY2:
return 3;
315 case POLY3:
return 4;
316 case POLY4:
return 5;
317 case EXPONENTIAL:
return 2;
318 case POWER:
return 2;
320 case RODBARD:
return 4;
321 case GAMMA_VARIATE:
return 4;
328 public static double f(
int fit,
double[] p,
double x) {
331 return p[0] + p[1]*x;
333 return p[0] + p[1]*x + p[2]* x*x;
335 return p[0] + p[1]*x + p[2]*x*x + p[3]*x*x*x;
337 return p[0] + p[1]*x + p[2]*x*x + p[3]*x*x*x + p[4]*x*x*x*x;
339 return p[0]*Math.exp(p[1]*x);
344 return p[0]*Math.exp(p[1]*Math.log(x));
348 return p[0]*Math.log(p[1]*x);
354 ex = Math.exp(Math.log(x/p[2])*p[1]);
355 double y = p[0]-p[3];
359 if (p[0] >= x)
return 0.0;
360 if (p[1] <= 0)
return -100000.0;
361 if (p[2] <= 0)
return -100000.0;
362 if (p[3] <= 0)
return -100000.0;
364 double pw = Math.pow((x - p[0]), p[2]);
365 double e = Math.exp((-(x - p[0]))/p[3]);
369 if (tmp<0.001) tmp = 0.001;
370 return p[0]+p[1]*Math.log(tmp);
385 double[] residuals =
new double[numPoints];
386 for (
int i = 0; i < numPoints; i++)
387 residuals[i] = yData[i] -
f(fit, params, xData[i]);
394 public double getSumResidualsSqr() {
396 return sumResidualsSqr;
402 double sd = Math.sqrt(getSumResidualsSqr() / numVertices);
411 for (
int i = 0; i < numPoints; i++) sumY += yData[i];
412 double mean = sumY / numVertices;
413 double sumMeanDiffSqr = 0.0;
415 double fitGoodness = 0.0;
416 for (
int i = 0; i < numPoints; i++) {
417 sumMeanDiffSqr += sqr(yData[i] - mean);
419 if (sumMeanDiffSqr > 0.0 && degreesOfFreedom != 0)
420 fitGoodness = 1.0 - (getSumResidualsSqr() / degreesOfFreedom) * ((numParams) / sumMeanDiffSqr);
429 StringBuffer results =
new StringBuffer(
"\nNumber of iterations: " +
getIterations() +
431 "\nSum of residuals squared: " + getSumResidualsSqr() +
432 "\nStandard deviation: " +
getSD() +
437 for (
int i = 0; i < numParams; i++) {
438 results.append(
"\n" + pChar +
" = " + pVal[i]);
441 return results.toString();
444 double sqr(
double d) {
return d * d; }
447 void sumResiduals (
double[] x) {
449 for (
int i = 0; i < numPoints; i++) {
450 x[numParams] = x[numParams] + sqr(
f(fit,x,xData[i])-yData[i]);
457 for (
int i = 0; i < numVertices; i++)
458 simp[worst][i] = next[i];
463 for (
int i = 0; i < numVertices; i++) {
464 if (simp[i][numParams] < simp[best][numParams]) best = i;
465 if (simp[i][numParams] > simp[worst][numParams]) worst = i;
468 for (
int i = 0; i < numVertices; i++) {
470 if (simp[i][numParams] > simp[nextWorst][numParams]) nextWorst = i;
507 public static int getMax(
double[] array) {
508 double max = array[0];
510 for(
int i = 1; i < array.length; i++) {