public abstract class LinearCoefficientFit extends DataFit {
    
    Numerical numerical = new Numerical();

    protected double[] modelTerms;

    public LinearCoefficientFit(int n) { 
	super(n); 	
    }
            
    public abstract double[] getTerms(double x);

    public double valueAt(double x) {
	double[] term = getTerms(x);
	double value = 0.0;
	for(int i=0; i<parameter.length; i++) value += parameter[i] * term[i];
	return value;
    }

    public double varianceAt(double x) {
	double[] term = getTerms(x);
	double var = 0.0;
	for(int i=0; i<term.length; i++) var += covar[i][i] * term[i] * term[i];
	return var;
    }

    private double[][] beta;
    public void fit(double x[], double y[], double sigma[]) throws IllegalStateException
    {
	int modelParms = size();
	
	if(beta == null) beta = new double[modelParms][1];
	else if(beta.length != modelParms) beta = new double[modelParms][1];

	// Count the number of fitted parms
	int fittedParms = countFitted();
	if(fittedParms == 0) throw new IllegalStateException("lfit: no parameters to be fitted");

	// Prepare the necessary matrixes for the fitted parms
	for(int j=0; j < fittedParms ; j++) {
	    for(int k=0; k < fittedParms; k++) covar[j][k]=0.0;
	    beta[j][0]=0.0;
	} 
 
	// Go through the data points
	for(int i=0; i < x.length; i++) if(sigma[i] > 0.0) {
	    double[] modelTerm = getTerms(x[i]);
	    double ym = y[i];
	    // Remove the unfitted part of the model
	    if(fittedParms < modelParms) {
		for(int j=0; j < modelParms; j++)
		    if(!isFitted[j]) ym -= parameter[j] * modelTerm[j];
	    }
	    double inverseSigma2= 1.0 / (sigma[i]*sigma[i]);
	    for(int j=0,l=0; l < modelParms; l++) {
		if(isFitted[l]) {
		    double weight = modelTerm[l] * inverseSigma2;
		    for(int k=0,m=0; m <= l; m++)
			if(isFitted[m]) covar[j][k++] += weight * modelTerm[m];
		    beta[j++][0] += ym * weight;
		}
	    }
	}

	// Symmetrize the covariance matrix
	for(int j=1; j < fittedParms; j++)
	    for(int k=0; k < j; k++)
		covar[k][j] = covar[j][k];
	
	numerical.gaussj(covar, beta);

	for(int j=-1,l=0; l < modelParms; l++)
	    if(isFitted[l]) parameter[l] = beta[++j][0];

	// sort the covarinace matrix
	covsrt();
    }
}
