package de.tud.inf.operator.fingerprints.lnf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.table.AttributeFactory;
import com.rapidminer.example.table.DataRow;
import com.rapidminer.example.table.DataRowFactory;
import com.rapidminer.example.table.MemoryExampleTable;
import com.rapidminer.operator.IOObject;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeDouble;
import com.rapidminer.parameter.ParameterTypeInt;
import com.rapidminer.parameter.ParameterTypeString;
import com.rapidminer.parameter.conditions.EqualTypeCondition;
import com.rapidminer.tools.Ontology;
import de.tud.inf.example.set.ComplexExampleSet;
import de.tud.inf.example.set.attributevalues.ComplexValueFactory;
import de.tud.inf.example.set.attributevalues.DataMapValue;
import de.tud.inf.example.set.attributevalues.MapValue;
import de.tud.inf.example.table.ComplexAttribute;
import de.tud.inf.example.table.MapAttribute;
import de.tud.inf.operator.fingerprints.ProcessStatistics;
public class LnfCreation extends Operator {
public static final String PARAMETER_MAP_NAME = "map_attribute_name";
public static final String PARAMETER_WINDOW_SIZE = "window_size";
public static final String PARAMETER_STEP_SIZE = "step_size";
public static final String PARAMETER_NEIGHBOURHOOD = "neighbourhood";
public static final String PARAMETER_RADIUS = "radius";
public static final String PARAMETER_ROTATION = "rotation";
public LnfCreation(OperatorDescription description) {
super(description);
}
@Override
public IOObject[] apply() throws OperatorException {
//exampleSet of all map values
ComplexExampleSet inputSet = getInput(ComplexExampleSet.class);
MapValue mv = null;
MapAttribute mapAttr = (MapAttribute) inputSet.getAttributes().get(getParameterAsString(PARAMETER_MAP_NAME));
//lnf attribute
List<Attribute> attributeList = new ArrayList<Attribute>(1);
ComplexAttribute lnfAttribute = (ComplexAttribute)AttributeFactory.createAttribute("LNF", Ontology.DATA_MAP_STRING);
attributeList.add(lnfAttribute);
MemoryExampleTable outputTable = new MemoryExampleTable(attributeList);
DataRowFactory factory = new DataRowFactory(DataRowFactory.TYPE_DOUBLE_ARRAY, ',');
Iterator<Example> it = inputSet.iterator();
Example e;
DataMapValue mValue = (DataMapValue)ComplexValueFactory.getComplexValueFunction(lnfAttribute);
while (it.hasNext()) {
e = it.next();
mv = e.getMapValue(mapAttr);
// calculate x and y size (map sorted by x,y)
TreeMap<String, Integer> symbolMap = new TreeMap<String, Integer>();
int windowSize;
if (getParameterAsInt(PARAMETER_NEIGHBOURHOOD) < 3)
windowSize = getParameterAsInt(PARAMETER_WINDOW_SIZE);
else
windowSize = 2 * getParameterAsInt(PARAMETER_RADIUS) + 1;
int stepSize = getParameterAsInt(PARAMETER_STEP_SIZE);
// nr of x values
int nrow = mv.getDimension()[0];
// nr of y values
int ncol = mv.getDimension()[1];
for (int i = 0; i <= nrow - windowSize; i += stepSize)
for (int j = 0; j <= ncol - windowSize; j += stepSize) {
//symbolList for each step through one array
List<String> symbolList = new ArrayList<String>();
// line 91
// boundary neighbourhood
//here numeric values are are read from map
if (getParameterAsInt("neighbourhood") == 2) {
String surroundSymbols = "";
// get only surrounding pixels
for (int m = 0; m < windowSize; m++)
surroundSymbols = surroundSymbols
+ mv.getStringValueAtId(i, j + m);
for (int m = 1; m < windowSize; m++)
surroundSymbols = surroundSymbols
+ mv.getStringValueAtId(i + m, j + windowSize
- 1);
for (int m = 1; m < windowSize; m++)
surroundSymbols = surroundSymbols
+ mv.getStringValueAtId(i + windowSize - 1, j
+ windowSize - 1 - m);
for (int m = 1; m < windowSize - 1; m++)
surroundSymbols = surroundSymbols
+ mv.getStringValueAtId(i + windowSize - 1
- m, j);
symbolList.add(surroundSymbols);
// line 108
// rotate pixels
if (getParameterAsInt(PARAMETER_ROTATION) == 1) {
int stringLength = surroundSymbols.length();
String s = "";
for (int l = 0; l < stringLength - 1; l++) {
s = "";
for (int k = 1; k <= stringLength; k++) {
s = s
+ surroundSymbols.charAt(k
% stringLength);
}
symbolList.add(s);
surroundSymbols = s;
}
}
}
// ring neighbourhood
//for neighbourhood > 3 string values are are read from map
else if (getParameterAsInt("neighbourhood") == 3) {
int radius = getParameterAsInt(PARAMETER_RADIUS);
int numberOfPoints = getParameterAsInt("points");
int k = i + radius;
int l = j + radius;
double[] points = getCircle(mv, k, l, radius,
(double) numberOfPoints);
// quantizise
String symbols = "";
double q = getParameterAsDouble("quantization step size");
char startSymbol = 'm';
for (int m = 0; m < points.length; m++) {
double z = points[m];
if (z >= 0) {
double quantile = q;
char symbol = startSymbol;
while (z >= quantile) {
quantile += q;
symbol++;
}
symbols += new Character(symbol).toString();
} else if (z < 0) {
double quantile = 0 - q;
char symbol = startSymbol;
symbol--;
while (z <= quantile) {
quantile -= q;
symbol--;
}
symbols += new Character(symbol).toString();
}
}
symbolList.add(symbols);
}
// circle neighbourhood
//for neighbourhood > 3 string values are are read from map
else if (getParameterAsInt("neighbourhood") == 4) {
int radius = getParameterAsInt("radius");
int numberOfPoints = getParameterAsInt("points");
int k = i + radius;
int l = j + radius;
List<double[]> pointsList = new ArrayList<double[]>();
for (int a = 1; a <= radius; a++) {
double[] points = getCircle(mv, k, l, a,
(double) numberOfPoints);
pointsList.add(points);
}
// add center pixel
pointsList.add(new double[] { mv.getValueAtId(k, l) });
// quantizise
List<String> qList = new ArrayList<String>();
for (double[] points : pointsList) {
String symbols = "";
double q = getParameterAsDouble("quantization step size");
char startSymbol = 'm';
for (int m = 0; m < points.length; m++) {
double z = points[m];
if (z >= 0) {
double quantile = q;
char symbol = startSymbol;
while (z >= quantile) {
quantile += q;
symbol++;
}
symbols += new Character(symbol).toString();
} else if (z < 0) {
double quantile = 0 - q;
char symbol = startSymbol;
symbol--;
while (z <= quantile) {
quantile -= q;
symbol--;
}
symbols += new Character(symbol).toString();
}
}
qList.add(symbols);
}
String s = "";
for (String symbols : qList)
s += symbols;
symbolList.add(s);
// rotate
if (getParameterAsInt("rotation") == 1) {
for (int a = 0; a < numberOfPoints - 1; a++) {
String stringCon = "";
for (int b = 0; b < qList.size() - 1; b++)
stringCon += qList.get(b).substring(a + 1,
numberOfPoints)
+ qList.get(b).substring(0, a + 1);
symbolList.add(stringCon
+ qList.get(qList.size() - 1));
}
}
}
else {
String symbols = "";
if ((windowSize == 3) && (getParameterAsInt("neighbourhood") == 0)) {
symbols = symbols + mv.getStringValueAtId(i+1,j) + mv.getStringValueAtId(i,j+1) + mv.getStringValueAtId(i+1,j+1) + mv.getStringValueAtId(i+2,j+1) + mv.getStringValueAtId(i+1,j+2);
} else {
for (int k=0; k<windowSize; k++)
{
for (int l=0; l<windowSize; l++)
{
symbols = symbols + mv.getStringValueAtId(i+k,j+l);
}
}
}
symbolList.add(symbols);
// rotate window 4 times
if (getParameterAsInt("rotation") == 1)
{
//180 degrees
String symbols2 = "";
for (int z = (symbols.length() - 1); z >= 0; z--)
symbols2 += symbols.charAt(z);
symbolList.add(symbols2);
// 270 degrees
String symbols3 = "";
if ((getParameterAsInt("neighbourhood") == 0) && (windowSize == 3)) {
symbols3 += "" + symbols.charAt(1) + symbols.charAt(4) + symbols.charAt(2) + symbols.charAt(0) + symbols.charAt(3);
}
else {
for (int y = windowSize - 1; y >= 0; y--){
for (int z = 0; z < Math.pow(windowSize,2); z += windowSize)
symbols3 += symbols.charAt(z+y);
}
}
symbolList.add(symbols3);
// 90 degrees
String symbols4 = "";
for (int z = (symbols3.length() - 1); z >= 0; z--)
symbols4 += symbols3.charAt(z);
symbolList.add(symbols4);
// rotate 3x3 window (and eight-neighbourhood) 8 times
if ((windowSize == 3) && (getParameterAsInt("neighbourhood") == 1))
{
String symbols5 = "" + symbols.charAt(3) + symbols.charAt(0) + symbols.charAt(1) + symbols.charAt(6) + symbols.charAt(4) + symbols.charAt(2) + symbols.charAt(7) + symbols.charAt(8) + symbols.charAt(5);
symbolList.add(symbols5);
String symbols6 = "";
for (int z = (symbols5.length() - 1); z >= 0; z--)
symbols6 += symbols5.charAt(z);
symbolList.add(symbols6);
String symbols7 = "" + symbols.charAt(7) + symbols.charAt(6) + symbols.charAt(3) + symbols.charAt(8) + symbols.charAt(4) + symbols.charAt(0) + symbols.charAt(5) + symbols.charAt(2) + symbols.charAt(1);
symbolList.add(symbols7);
String symbols8 = "";
for (int z = (symbols7.length() - 1); z >= 0; z--)
symbols8 += symbols7.charAt(z);
symbolList.add(symbols8);
}
}
} //end if (default neighbourhood)
Collections.sort(symbolList);
String symbols = symbolList.get(0);
Integer number;
if ((number = symbolMap.get(symbols)) != null)
{
number++;
symbolMap.put(symbols, number);
}
else
symbolMap.put(symbols, 1);
} // end iteration through one map
// calculate relative frequencies
int xSize = nrow;
int ySize = ncol;
double totalNum = ((xSize - windowSize) + 1) * ((ySize - windowSize) + 1);
double minFreq = getParameterAsDouble("min relative frequency");
double relValue = 0;
Map<String,Double> resultMap = new HashMap<String,Double>();
for (Map.Entry<String, Integer> mapEntry: symbolMap.entrySet())
{
relValue = (double)mapEntry.getValue()/totalNum;
if (relValue > minFreq)
{
resultMap.put(mapEntry.getKey(),relValue);
}
}
mValue.setStringMap(resultMap);
//create new dataRow in outputexampleTable
DataRow dataRow = factory.create(lnfAttribute.getParameterCount());
outputTable.addDataRow(dataRow);
dataRow.set(lnfAttribute,mValue);
// some statistics
//war vorher fingerprintbuffer.
//ProcessStatistics.getInstance().addFingerprintStringLength(resultMap.size());
ProcessStatistics.getInstance().addNumSymbolVectors(symbolMap.size());
} // end iteration through all maps in exampleSet
ExampleSet output = outputTable.createExampleSet();
return new IOObject[] {output};
}
/**
* @param mv
* map value
* @param i
* current x position
* @param j
* current y position
* @param r
* radius of circle
* @param p
* number of points
* @return
*/
private double[] getCircle(MapValue mv, int i, int j, double R, double P) {
double[] result = new double[(int) P];
for (double p = 1; p <= P; p++) {
double x = -R * Math.sin(2.0 * Math.PI * p / P);
double y = R * Math.cos(2.0 * Math.PI * p / P);
if ((int) (x * 10000.0) == 0)
x = 0;
if ((int) (y * 10000.0) == 0)
y = 0;
double x1 = Math.floor(x);
double x2 = Math.ceil(x);
double y1 = Math.floor(y);
double y2 = Math.ceil(y);
// hack for -0
if (x1 == -0)
x1 = 0;
if (x2 == -0)
x2 = 0;
if (y1 == -0)
y1 = 0;
if (y2 == -0)
y2 = 0;
if ((x1 == x2) && (y1 == y2))
result[(int) p - 1] = mv.getValueAtId(i + (int) x,
(j + (int) y));
else
result[(int) p - 1] = interpolate(x1, x2, y1, y2, mv
.getValueAtId((int) (i + x1), (int) (j + y1)), mv
.getValueAtId((int) (i + x2), (int) (j + y1)), mv
.getValueAtId((int) (i + x1), (int) (j + y2)), mv
.getValueAtId((int) (i + x2), (int) (j + y2)), x, y);
}
return result;
}
private double interpolate(double x1, double x2, double y1, double y2,
double q11, double q21, double q12, double q22, double x, double y) {
// double quo = (x2 - x1)*(y2 -y1);
double result = 0.0;
result += q11 * (x2 - x) * (y2 - y);
result += q21 * (x - x1) * (y2 - y);
result += q12 * (x2 - x) * (y - y1);
result += q22 * (x - x1) * (y - y1);
return result;
}
@Override
public Class<?>[] getInputClasses() {
return new Class[] { ComplexExampleSet.class };
}
@Override
public Class<?>[] getOutputClasses() {
return new Class[] { ExampleSet.class };
}
/**
* Returns a list of ParameterTypes describing the parameters of this
* operator.
*/
public List<ParameterType> getParameterTypes() {
List<ParameterType> types = super.getParameterTypes();
types.add(new ParameterTypeString(PARAMETER_MAP_NAME, "", "map"));
types.add(new ParameterTypeCategory(PARAMETER_ROTATION, "",new String[] { "no", "yes" }, 0));
types.add(new ParameterTypeCategory(PARAMETER_NEIGHBOURHOOD, "",new String[] { "four-neighbourhood", "eight-neighbourhood","boundary", "ring", "circle" }, 1));
ParameterType type = new ParameterTypeInt(PARAMETER_WINDOW_SIZE, "", 2,100, 3);
type.registerDependencyCondition(new EqualTypeCondition(this,PARAMETER_NEIGHBOURHOOD, true, 0, 1, 2));
types.add(type);
type = new ParameterTypeInt(PARAMETER_RADIUS, "", 1, Integer.MAX_VALUE,1);
type.registerDependencyCondition(new EqualTypeCondition(this,PARAMETER_NEIGHBOURHOOD, true, 3, 4));
types.add(type);
type = new ParameterTypeInt("points", "", 4, Integer.MAX_VALUE, 8);
type.registerDependencyCondition(new EqualTypeCondition(this,
PARAMETER_NEIGHBOURHOOD, true, 3,4)); types.add(type);
type = new ParameterTypeDouble("quantization step size","only for ring/circle neighbourhoods", 0, 10, 1);
type.registerDependencyCondition(new EqualTypeCondition(this,PARAMETER_NEIGHBOURHOOD, true, 3, 4));
types.add(type);
types.add(new ParameterTypeInt(PARAMETER_STEP_SIZE, "", 1, 1000, 1));
types.add(new ParameterTypeDouble("min relative frequency", "", 0,1, 0));
return types;
}
}