package joptima;

import joptima.functions.Sum2D;

import java.util.Iterator;

/**
 * 

* χ² fitter. * This class can be passed to a {@link Minimizer} to minimize χ² of a * sum of one or more functions fit to the given two-dimensional data set. * Error bars may be provided for the data points if the data has * compounded errors that are Gaussian. sqrt(z) errors are assumed otherwise. *

* *

* Note that the usual two-dimensional matrix of values is passed to this * function unfolded into a single array, i.e. the (x[i], y[i], z[i]) * tuple for an m by n histogram where z = f(x, y) will have indices running * from 0 through m * n - 1. *

* *

* A typical usage of this class would go as follows: *

 *   // The data points.
 *   double[] x = new double[]{  1,   2,   3,
 *                               1,   2,   3,
 *                               1,   2,   3};
 *   double[] y = new double[]{  1,   1,   1,
 *                               2,   2,   2,
 *                               3,   3,   3};
 *   double[] z = new double[]{1.1, 4.0, 8.7,
 *                             3.9,  16,  24,
 *                             9.2,  22,  38};
 *
 *   // The {@link Function} to fit to the data points.
 *   Function2D f = new Sum2D(new Quadratic(), new Quadratic);
 *
 *   ChiSquaredFitter2D fitter = new ChiSquaredFitter2D();
 *   fitter.setData(x, y, z);
 *   fitter.addFunction(f);
 *   Minimizer.minimize(fitter);
 *
 *   // At this point, if the fit converged, the {@link Function} f will have
 *   // its {@link Parameter}s set to the optimal values.
 * 
*

* * @author Dejan Vucinic <dvucinic@users.sourceforge.net> */ public class ChiSquaredFitter2D extends Fitter { private double[] xpoint, ypoint, zpoint; private double[] zerror = null; /** * Constructor. */ public ChiSquaredFitter2D() { } /** * Constructor. * Assumes sqrt(z) errors. * @param x the x coordinates of points * @param y the y coordinates of points * @param z the z coordinates of points */ public ChiSquaredFitter2D(double[] x, double[] y, double[] z) { setData(x, y, z); } /** * Constructor. * @param x the x coordinates of points * @param y the y coordinates of points * @param z the z coordinates of points * @param errors the error bars on z coordinates of points */ public ChiSquaredFitter2D(double[] x, double[] y, double[] z, double[] errors) { setData(x, y, z, errors); } /** * Constructor. * Assumes sqrt(y) errors. * @param x the x coordinates of points * @param y the y coordinates of points * @param z the z coordinates of points * @param f the {@link Function} to fit to the given set of points */ public ChiSquaredFitter2D(double[] x, double[] y, double[] z, Function f) { this(x, y, z); addFunction(f); } /** * Constructor. * @param x the x coordinates of points * @param y the y coordinates of points * @param z the z coordinates of points * @param errors the error bars on z coordinates of points * @param f the {@link Function} to fit to the given set of points */ public ChiSquaredFitter2D(double[] x, double[] y, double[] z, double[] errors, Function f) { this(x, y, z, errors); addFunction(f); } /** * Invalidates this signature of this method on the superclass. * This form throws an UnsupportedOperationException() because * its meaning is ambiguous for a 2D fitter. Use {@link #addFunction} * instead. */ public void addFunction(Function f) { throw new UnsupportedOperationException("Adding a 1D function to a 2D fitter is ambiguous. Use " + "addFunction1Dx() or addFunction1Dy() instead."); } /** * Adds a {@link Function2D} to this {@link Fitter}. */ public void addFunction(Function2D f) { m_functions.add(f); m_nparameters += f.getParameters().length; } /** * Adds a one-dimensional {@link Function} to this {@link Fitter}. * This form makes 2D extension of the given function along the y-axis, * i.e. makes a Sum2D(function, null). * @param f the one-dimensional function to extend along the y-axis */ public void addFunction1Dx(Function f) { m_functions.add(new Sum2D(f, null)); m_nparameters += f.getParameters().length; } /** * Adds a one-dimensional {@link Function} to this {@link Fitter}. * This form makes 2D extension of the given function along the x-axis, * i.e. makes a Sum2D(null, function). * @param f the one-dimensional function to extend along the x-axis */ public void addFunction1Dy(Function f) { m_functions.add(new Sum2D(null, f)); m_nparameters += f.getParameters().length; } /** * Fit the sum of functions to this set of points. * Assumes sqrt(y) error bars. * @param x the x coordinates of points * @param y the y coordinates of points * @param z the z coordinates of points */ public void setData(double[] x, double[] y, double[] z) { xpoint = x; ypoint = y; ypoint = z; zerror = null; } /** * Fit the sum of functions to this set of points. * @param x the x coordinates of points * @param y the y coordinates of points * @param z the z coordinates of points * @param errors the error bars on y coordinates of points */ public void setData(double[] x, double[] y, double[] z, double[] errors) { xpoint = x; ypoint = y; zpoint = z; zerror = errors; } /** * Calculates the χ² given parameter values set by a {@link Minimizer} * using reflection. * The formula is: *
   *   for each point in the data set {
   *     f = 0
   *     for each {@link Function} {
   *       f += {@link Function#calculate}(x[point], y[point])
   *     }
   *     χ² += (y[point] - f)² / error[point]²
   *   }
   * 
*/ public double calculate() { double value = 0; for (int point = 0; point < xpoint.length; point++) { Iterator it = m_functions.iterator(); double fvalue = 0; while (it.hasNext()) { Function2D f = (Function2D) it.next(); fvalue += f.calculate(xpoint[point], ypoint[point]); } double chisq = (zpoint[point] - fvalue); chisq = chisq * chisq; if (null != zerror) chisq /= zerror[point] * zerror[point]; value += chisq; } return value; } }

Ads help maintain this website.