/*
* AbstractIFunction.java
*
* Created on February 18, 2004, 12:02 PM
*/
package hep.aida.ref.function;
import hep.aida.IModelFunction;
import hep.aida.IRangeSet;
import hep.aida.ref.Annotation;
import hep.aida.ref.ManagedObject;
import java.util.ArrayList;
/**
* AbstractIFunction is implementation of the IFunction.
* User has to implement "value" method.
* @author serbo
*/
public abstract class AbstractIFunction extends ManagedObject implements IModelFunction, Cloneable, FunctionDispatcher {
protected String[] variableNames;
protected String[] parameterNames;
protected String codeletString;
private Annotation annotation;
private int dimension;
private int numberOfParameters;
private ArrayList listeners = new ArrayList();
private RangeSet[] rangeSet;
protected double[] p;
protected double[] gradient;
/** No-argument constructor to be used for cloning.
* Created function can not be used directly
*/
public AbstractIFunction() {
super("");
String className = this.getClass().getName();
codeletString = "codelet:"+className+":classPath:";
}
/** Creates a new instance of AbstractIFunction
* with default variable names (x0, x1, ...)
* and default parameter names (p0, p1, ...)
*/
public AbstractIFunction(String title, int dimension, int numberOfParameters) {
this();
variableNames = new String[dimension];
for (int i=0; i<dimension; i++) { variableNames[i] = "x"+i; }
parameterNames = new String[numberOfParameters];
for (int i=0; i<numberOfParameters; i++) { parameterNames[i] = "par"+i; }
init(title);
}
/** Creates a new instance of AbstractIFunction
* with specified variable and parameter names.
* This constructor must be implemented by all subclasses
* in order for codelet-based creation to work properly
*/
public AbstractIFunction(String[] variableNames, String[] parameterNames) {
this("", variableNames, parameterNames);
}
public AbstractIFunction(String title, String[] variableNames, String[] parameterNames) {
this();
this.variableNames = variableNames;
this.parameterNames = parameterNames;
init(title);
}
public Object clone() {
try {
AbstractIFunction copy = (AbstractIFunction) super.clone();
copy.codeletString = codeletString;
copy.dimension = dimension;
copy.numberOfParameters = numberOfParameters;
copy.variableNames = (String[]) variableNames.clone();
copy.parameterNames = (String[]) parameterNames.clone();
copy.p = (double[]) p.clone();
copy.gradient = (double[]) gradient.clone();
copy.listeners = (ArrayList) listeners.clone();
copy.annotation = new Annotation(annotation);
copy.rangeSet = new RangeSet[dimension()];
for (int i=0; i<dimension(); i++) {
double[] min = (double[]) rangeSet[i].lowerBounds().clone();
double[] max = (double[]) rangeSet[i].upperBounds().clone();
copy.rangeSet[i] = new RangeSet(min, max);
}
return copy;
} catch (Exception e) {
throw new RuntimeException("Error while cloning "+codeletString, e);
}
}
// Service methods
protected void init(String title) {
dimension = variableNames.length;
numberOfParameters = parameterNames.length;
p = new double[numberOfParameters];
gradient = new double[dimension];
rangeSet = new RangeSet[dimension()];
for (int i=0; i<dimension(); i++)
rangeSet[i] = new RangeSet();
if (title == null) title = "";
annotation = new Annotation();
annotation.addItem(Annotation.titleKey, title);
annotation.setFillable(true);
String className = this.getClass().getName();
String vn = "";
String pn = "";
for (int i=0; i<variableNames.length; i++) vn = vn + "," + variableNames[i];
for (int i=0; i<parameterNames.length; i++) pn = pn + "," + parameterNames[i];
codeletString = "codelet:"+className+":classPath:" + vn + ":" + pn;
}
public void setCodeletString(String str) { codeletString = str; }
// IFunction methods
/** Provide value for your function here. Something like:
* return p[0]+p[1]*v[0]+p[2]*v[0]*v[0];
*/
public abstract double value(double[] v);
public boolean providesGradient() {
return false;
}
public double[] gradient(double[] values) {
return gradient;
}
public String codeletString() {
return codeletString;
}
public hep.aida.IAnnotation annotation() {
return annotation;
}
public int dimension() {
return dimension;
}
public int indexOfParameter(String str) {
int index = -1;
for (int i=0; i<numberOfParameters; i++) {
if (str.equals(parameterNames[i])) {
index = i;
break;
}
}
return index;
}
public int numberOfParameters() {
return numberOfParameters;
}
public double parameter(String str) {
int index = indexOfParameter(str);
if (index == -1) throw new IllegalArgumentException("Parameter \""+str+"\" does not exist");
return p[index];
}
public String[] parameterNames() {
return parameterNames;
}
public double[] parameters() {
return p;
}
public void setParameter(String str, double param) throws java.lang.IllegalArgumentException {
int index = indexOfParameter(str);
if (index == -1) throw new IllegalArgumentException("Parameter \""+str+"\" does not exist");
p[index] = param;
notifyFunctionChanged(new FunctionChangedEvent( FunctionChangedEvent.PARAMETER_VALUE_CHANGED ) );
}
public void setParameters(double[] pars) throws java.lang.IllegalArgumentException {
if (pars.length != numberOfParameters)
throw new IllegalArgumentException("Wrong number of input parameters:"+pars.length+", must be "+numberOfParameters);
for (int i=0; i<numberOfParameters; i++) p[i] = pars[i];
notifyFunctionChanged(new FunctionChangedEvent( FunctionChangedEvent.PARAMETER_VALUE_CHANGED ) );
}
public void setTitle(String title) throws java.lang.IllegalArgumentException {
annotation.setValue(Annotation.titleKey, title);
notifyFunctionChanged(new FunctionChangedEvent( FunctionChangedEvent.TITLE_CHANGED ) );
}
public String title() {
return annotation.value(Annotation.titleKey);
}
public String variableName(int index) {
return variableNames[index];
}
public String[] variableNames() {
return variableNames;
}
public void excludeNormalizationAll() {
for (int i=0; i<dimension(); i++) rangeSet[i].excludeAll();
notifyFunctionChanged(new FunctionChangedEvent( FunctionChangedEvent.RANGE_CHANGED ) );
}
public void includeNormalizationAll() {
for (int i=0; i<dimension(); i++) rangeSet[i].includeAll();
notifyFunctionChanged(new FunctionChangedEvent( FunctionChangedEvent.RANGE_CHANGED ) );
}
public boolean isNormalized() {
return false;
}
public IRangeSet normalizationRange(int iAxis) {
return rangeSet[iAxis];
}
public void normalize(boolean param) {
}
public double[] parameterGradient(double[] values) {
return null;
}
public boolean providesNormalization() {
return false;
}
public boolean providesParameterGradient() {
return false;
}
public String normalizationParameter() {
throw new UnsupportedOperationException("This method needs to be overwritten to perform unbinned fits");
}
public boolean isEqual(hep.aida.IFunction iFunction) {
throw new UnsupportedOperationException("Not implemented");
}
public void addFunctionListener( FunctionListener listener ) {
listeners.add(listener);
}
public void removeFunctionListener( FunctionListener listener ) {
listeners.remove(listener);
}
void notifyFunctionChanged(FunctionChangedEvent event) {
for ( int i = 0; i < listeners.size(); i++ )
( (FunctionListener) listeners.get(i) ).functionChanged(event);
}
}