package jas.hist; import jas.util.DoubleWithError; public abstract class Fittable1DFunction extends Basic1DFunction implements ExtendedStatistics { public abstract double valueAt(double x, double[] param) throws FunctionValueUndefined; abstract public void setFit(Fitter fit, double[] param) throws InvalidFunctionParameter; public boolean[] getIncludeParametersInFit() { initIncludeParametersInFit(getParameterNames().length); return m_fitParms; } public void clearFitParams() { m_fitParms = null; } public void setIncludeParameterInFit(int index, boolean value) { initIncludeParametersInFit(getParameterNames().length); m_fitParms[index] = value; clearFit(); setChanged(); } protected void initIncludeParametersInFit(int nParameters) { if (m_fitParms == null || m_fitParms.length != nParameters) { m_fitParms = new boolean[nParameters]; for (int i=0; i<m_fitParms.length; i++) m_fitParms[i] = true; } } /** * Calculates the partial derivative of the function with respect to each parameter * at point x. This is a non-analytical calculation which can be overriden by subclasses * which wish to provide an analytical calculation * @exception FunctionValueUndefined if the function is not defined for <code>x</code> */ public double[] getDerivatives(double x, double[] a) throws FunctionValueUndefined { int nterms = a.length; double[] result = new double[nterms]; double[] deltaA = getParameterDeltas(); for (int j=0; j<nterms; j++) { double old = a[j]; double delta = deltaA[j]; a[j] = old + delta; double y = valueAt(x,a); a[j] = old - delta; result[j] = (y - valueAt(x,a))/(2*delta); a[j] = old; } return result; } private double[] getParameterDeltas() { double[] a = (double[]) getParameterValues().clone(); for (int i=0; i<a.length; i++) a[i] = 1e-7; return a; } public Fitter getFit() { return m_fit; } protected void setFit(Fitter fit) { m_fit = fit; } public void clearFit() { Fitter old = m_fit; // avoid race condition in case we are called recursively // We must tell the fitter that it should leave us alone if (old != null) { m_fit = null; old.dispose(); } } protected void destroy() { clearFit(); super.destroy(); } public String[] getStatisticNames() { //adding Chi squared to end of statnames array String[] statnames = null; if(m_fit != null){ if(getParameterNames()!=null){ statnames = new String[getParameterNames().length+1]; for(int i=0;i<getParameterNames().length;i++){ statnames[i]=getParameterNames()[i]; } }else statnames = new String[1]; statnames[statnames.length -1]=chi2; return statnames; }else return statnames = super.getStatisticNames(); } public double getStatistic(String name) { if (name.equals(chi2)) return m_fit.getChiSquared(); else return super.getStatistic(name); } public Object getExtendedStatistic(String name) { if(m_fit!=null) { boolean[] inFit = getIncludeParametersInFit(); int count = 0; for ( int i = 0; i < inFit.length; i++ ) { if ( name.equals(getParameterNames()[i]) ) { if ( inFit[i] ) return new DoubleWithError(getParameterValues()[i],m_fit.getParameterSigmas()[count]); else return format.format(getParameterValues()[i])+" Fixed"; } if ( inFit[i] ) count++; } } return null; } private final static String chi2 = "\u03c7\u00b2"; private Fitter m_fit; private boolean[] m_fitParms; private java.text.NumberFormat format = java.text.NumberFormat.getInstance(); }