package fr.unistra.pelican.util.data;
import java.io.Serializable;
import java.lang.reflect.Method;
import fr.unistra.pelican.Descriptor;
import fr.unistra.pelican.util.Offset;
import fr.unistra.pelican.util.data.distances.Distance;
/**
* Abstract class representing data to be used in PELICAN. Possible use is to
* consider data as feature and to compute distance between features.
*
* The exact data structure has to be specified in the subclasses.
*
* @author lefevre, weber
* @author Régis Witz (clone,toString,getParsedInstance)
*
*/
public abstract class Data implements Cloneable, Serializable {
private static final long serialVersionUID = -1244611776868304298L;
/**
* The descriptor used to produce the data (filled automatically when
* computing the descriptor). Stores the class rather than the object seems is
* more efficient.
*/
Class<Descriptor> descriptor;
/**
* Returns the descriptor used to produce the data
*
* @return the descriptor used to produce the data
*/
public Class<Descriptor> getDescriptor() {
return descriptor;
}
/**
* Set the descriptor used to produce the data
*
* @param d
* the descriptor used to produce the data
*/
public void setDescriptor(Class<Descriptor> d) {
descriptor = d;
}
/**
* Abstract getter to be overriden by subclasses
*
* @return the values contained in the data
*/
public abstract Object getValues();
/**
* Abstract setter to be overriden by subclasses
* @param values new values to be set in the object
*/
public abstract void setValues(Object values);
/**
* Abstract method defining the default distance measure to be overriden by
* subclasses
*
* @param data
* some data to be compared to
* @return the distance between the object and data
*/
public abstract double distance(Data data);
/**
* Computes the similarity measure between the object and the given data
*
* @param data
* some data to be compared to
* @return the similarity measure between the object and data
*/
public double similarityTo(Data data)
{
return 1-distanceTo(data);
}
/**
* Computes the distance between the object and the given data
*
* @param data
* some data to be compared to
* @return the distance between the object and data
*/
public double distanceTo(Data data) {
Class<Descriptor> descriptor = getDescriptor();
Method method = null;
double result = -1;
// Première recherche : dans descriptor
if (descriptor != null)
try {
method = descriptor.getMethod("distance", Data.class, Data.class);
result = (Double) method.invoke(null, this, data);
} catch (Exception e) {
// Si une erreur lors de l'appel qui n'est pas un NoSuchMethodException
if (!(e instanceof NoSuchMethodException))
e.printStackTrace();
}
if (result == -1)
// Seconde recherche : dans data
try {
method = getClass().getMethod("distance", Data.class);
result = (Double) method.invoke(this, data);
} catch (Exception e) {
// Si une erreur lors de l'appel qui n'est pas un NoSuchMethodException
if (!(e instanceof NoSuchMethodException))
e.printStackTrace();
else
System.err.println("Méthode distance absente de " + getDescriptor()
+ " et de " + getClass());
}
return result;
}
/**
* Computes the distance between the two data
*
* @param data1
* First data
* @param data2
* Second data
* @return the distance between the two data
*/
public static double distanceBetween(Data data1, Data data2) {
return data1.distanceTo(data2);
}
/**
* Computes the distance between the object and the data using a given
* distance measure
*
* @param data
* some data to be compared to
* @param dist
* A distance measure to be used
* @return the distance between the two data
*/
public double distanceTo(Data data, Distance dist) {
return dist.distance(this, data);
}
/**
* Computes the distance between the two data using a given distance measure
*
* @param data1
* First data
* @param data2
* Second data
* @param dist
* A distance measure to be used
* @return the distance between the two data
*/
public static double distanceBetween(Data data1, Data data2, Distance dist) {
return dist.distance(data1, data2);
}
/**
* Computes the distance between the two data using a given distance measure
*
* @param data1
* First data
* @param data2
* Second data
* @param distanceName
* The class representing the distance measure to be used
* @param params
* The required parameters to create the distance measure object
* @return the distance between the two data
*/
@SuppressWarnings("unchecked")
public static double distanceBetween(Data data1, Data data2, Class distanceName,
Object... params) {
return Distance.forName(distanceName, data1, params).distance(data1, data2);
}
/**
* Abstract method returning a String representation of the data to be
* overriden by subclasses
* @return See {@link String#toString}.
*/
public abstract String toString();
/**
* Abstract method used to check if two data are equals
*
* @param data
* to be compared to
* @return true if both data are equals, false otherwise
*/
public abstract boolean equals(Data data);
/** Why shouldn't a Data be cloneable ?
* @return Cloned data.
* @author Régis Witz
*/
public abstract Data clone();
/** Get a data instance described in <tt>input</tt>.
* This method is not abstract with respect to lazy coders.
* @param words words to parse
* @param offset offset in <tt>words</tt> with wich parsing is begun
* @return a new instance of Data
* @author Régis Witz
*/
public static Data getParsedInstance( String[] words, Offset offset ) { return null; };
}