package jas.hist;
class FitAdapter1D extends Fittable1DFunction
/*
* adapts a Fittable1DFunction
* for use by a Fitter class
*/
{
private double[] fitterParameters, functionParameters;
// functionParameters are the ones recognized by the
// function and are updated as the fitterParameters
// change
// fitterParameters are the ones recognized by the
// fitter and may be fewer if not all parameters
// are being fit
private boolean[] inFit; // whether the parameter is included
// in the fit
private Fittable1DFunction func;
public FitAdapter1D(Fittable1DFunction func)
{
this.func = func;
inFit = func.getIncludeParametersInFit();
functionParameters = func.getParameterValues();
double[] temp = new double[functionParameters.length];
// the possibly shortened list will be stored in temp
// functionParameters.length is the largest capacity
// that will be needed
int j = 0;
for (int i = 0; i < inFit.length; i++)
if (inFit[i])
temp[j++] = functionParameters[i];
// copy over parameters that are used in the fit
if (j == functionParameters.length)
// all parameters were included in the fit
fitterParameters = temp;
else
// the new array is shorter than the old one
{
fitterParameters = new double[j];
// j < functionParameters.length
// j = number of included parameters
for (int i = 0; i < j; i++)
fitterParameters[i] = temp[i];
// the array fitterParameters is identical
// to the array temp except that
// fitterParameters is shorter
}
}
public double[] getParameterValues()
{
return fitterParameters;
// this method is called by the fitter,
// so it returns the fitterParameters
}
public boolean[] getIncludedInFit()
{
return inFit;
}
public double[] getDerivatives(double x, double[] a) throws FunctionValueUndefined
{
updateParameters(a);
double[] fullAnswer = func.getDerivatives(x, functionParameters);
// fullAnswer must be reduced if one or more
// parameters is not being fit
if (functionParameters.length == fitterParameters.length)
// all parameters are being fit
return fullAnswer;
// else, a condensed answer must be returned
double[] condensedAnswer = new double[fitterParameters.length];
int i = 0;
for (int j = 0; j < fullAnswer.length; j++)
if (inFit[j])
condensedAnswer[i++] = fullAnswer[j];
return condensedAnswer;
}
public double valueAt(double x, double[] a) throws FunctionValueUndefined
{
updateParameters(a);
return func.valueAt(x, functionParameters);
}
public void setFit(Fitter f, double[] a) throws
InvalidFunctionParameter
{
updateParameters(a);
func.setFit(f, functionParameters);
}
private void updateParameters(double[] fitterParameters)
// using the fitterParameters, both this.fitterParameters
// and this.functionParameters are updated
{
this.fitterParameters = fitterParameters;
if (functionParameters.length == fitterParameters.length)
functionParameters = fitterParameters;
else
{
int i = 0;
for (int j = 0; j < functionParameters.length; j++)
{
if (inFit[j])
{
functionParameters[j] = fitterParameters[i++];
}
}
}
}
// I don't think the remaining methods
// will ever be called, but they are
// abstract methods in Basic1DFunction
// and must be included
public boolean[] getIncludeParametersInFit()
{
return inFit;
}
public String[] getParameterNames()
{
return func.getParameterNames();
}
public String getTitle()
{
return func.getTitle();
}
public void setParameter(int i, double d) throws InvalidFunctionParameter
{
if (fitterParameters.length == functionParameters.length)
func.setParameter(i, d);
else
for (int j = 0; j <= i; j++) if (!inFit[j]) i++;
func.setParameter(i, d);
/*
* The basic idea here (it's probably not
* obvious) is that i is the parameter
* taken from the shortened list. It
* must be increased by one for every
* parameter that is not in the fit
* and is below where it will eventually
* be.
*/
}
public double valueAt(double d) throws FunctionValueUndefined
{
return func.valueAt(d);
}
}