package de.tud.inf.example.set.attributevalues; import com.rapidminer.example.table.NominalMapping; import com.rapidminer.example.table.PolynominalMapping; import com.rapidminer.tools.Ontology; /** * this complex value encapsulates a map z = f(x,y), x and y are discrete and * equidistant point coordinates, z can be arbitrary * z values are stored in y-direction first, i.e zValues = {f(0,0), f(0,1),..., f(0,dimension[1], f(1,0)...) * @author Antje Gruner * */ public class MapValue implements ComplexValue { /** * step size in x and y direction */ private double[] spacing = new double[2]; /** * defines the maximum number of values to be displayed in data view */ private int mxPlotValues = 100; /** * minimal value of x and y */ private double[] origin = new double[2]; /** * number of entries within dimension */ private int[] dimension = new int[2]; /** * features z = f(x,y) of this map */ private double[] zValues = new double[0]; private NominalMapping nm; public MapValue() { } MapValue(double[] spacing, double[] origin, int[] dimension, double[] values, NominalMapping nm) { this.spacing = spacing; this.origin = origin; this.dimension = dimension; zValues = new double[dimension[0] * dimension[1]]; int min = Math.min(values.length, zValues.length); // set values for (int i = 0; i < min; i++) zValues[i] = values[i]; this.nm = nm; } MapValue(double[] spacing, double[] origin, int[] dimension, double[] values) { this(spacing,origin,dimension,values,null); } public double getDoubleValue() { return 0; } public String getStringRepresentation(int digits, boolean quoteWhitespace) { StringBuffer buf = new StringBuffer(); int plotNr = Math.min(zValues.length,mxPlotValues); if(nm == null){ switch (digits) { case UNLIMITED_NUMBER_OF_DIGITS: for (int i=0; i< plotNr;i++){ buf.append(zValues[i]); buf.append(" "); if(i % dimension[1] == (dimension[1])-1) buf.append("| "); } case DEFAULT_NUMBER_OF_DIGITS: for (int i=0; i< plotNr;i++){ buf.append(com.rapidminer.tools.Tools.formatIntegerIfPossible(zValues[i],-1)); buf.append(" "); if(i % dimension[1] == (dimension[1])-1) buf.append("| "); } default: for (int i=0; i< plotNr;i++){ buf.append(com.rapidminer.tools.Tools.formatIntegerIfPossible(zValues[i],digits)); buf.append(" "); if(i % dimension[1] == (dimension[1])-1) buf.append("| "); } } } else{ for (int i=0; i< plotNr;i++){ buf.append(nm.mapIndex((int)zValues[i])); buf.append(" "); if(i % dimension[1] == (dimension[1])-1) buf.append("| "); } } return buf.toString(); } public int getValueType() { return Ontology.MAP; } /** * returns z value according to x and y coordinate values * if the values is not directly given the z value will be interpolated * using a simple bilinear interpolation * @param x x coordinate * @param y y coordinate * @return z value */ public double getValueAt(double x, double y) { // do x and y lie in the grid? if(Math.IEEEremainder(x - origin[0], spacing[0]) == 0.0 && Math.IEEEremainder(y - origin[0], spacing[1]) == 0.0) { // -> yes int ix = (int) ((x - origin[0]) / spacing[0]); int iy = (int) ((y - origin[1]) / spacing[1]); return zValues[ix * dimension[1] + iy]; } else { // do a bilinear interpolation return getInterpolatedValue((x - origin[0]) / spacing[0], (y - origin[1]) / spacing[1]); } } /** * returns z value according to x and y index values in z array * @param x index of x coordinate * @param y index of y coordinate * @return z value */ public double getValueAtId(int idX, int idY) { return zValues[idX * dimension[1] + idY]; } public double getValueAtId(double idX,double idY) { //double x = origin[0] + idX*spacing[0]; //double y = origin[1] + idY*spacing[0]; return getInterpolatedValue(idX, idY); } /** * returns z string value according to x and y index values in z array * @param x index of x coordinate * @param y index of y coordinate * @return z value */ public String getStringValueAtId(int idX, int idY) { return nm.mapIndex((int)zValues[idX * dimension[1] + idY]); } /** * maps internal double values to String, call this method iff there is definitely an nominal mapping in map value * @param x * @param y * @return */ public String getStringValueAt(double x, double y) { int ix = (int) ((x - origin[0]) / spacing[0]); int iy = (int) ((y - origin[1]) / spacing[1]); return nm.mapIndex((int) zValues[ix * dimension[1] + iy]); } /** * * @param id position in z array * @return mapped value */ public String getStringValueAt(int id) { return nm.mapIndex((int)zValues[id]); } /** * * @param z * values of f(x,y) * @param o * origin * @param s * spacing * @param dim dimension vector (nr entries) */ public void setValues(double[] z, double[] o, double[] s, int[] dim, NominalMapping nm) { spacing[0] = s[0]; spacing[1] = s[1]; origin[0] = o[0]; origin[1] = o[1]; dimension[0] = dim[0]; dimension[1] = dim[1]; // create new map array zValues = new double[dimension[0] * dimension[1]]; int min = Math.min(z.length, zValues.length); // set values for (int i = 0; i < min; i++) zValues[i] = z[i]; this.nm = nm; } public double[] getSpacing() { return spacing; } public double[] getOrigin() { return origin; } public int[] getDimension() { return dimension; } public double[] getZValues() { return zValues; } public int getMapSize(){ return zValues.length; } public double getAverage(){ double sum =0; for(int i =0;i<zValues.length;i++) sum += zValues[i]; return sum/zValues.length; } public double getVariance(){ double avg = getAverage(); double squaredSum =0; double deviation; for(int i =0;i<zValues.length;i++) { deviation = zValues[i] - avg; squaredSum += deviation*deviation; } // squaredSum += zValues[i]*zValues[i]; return squaredSum / (zValues.length-1); } /** * returns maximum x and y values of map * @return */ public double[] getExtent(){ double[] ex = new double[2]; ex[0] = origin[0] + spacing[0]*(dimension[0]-1); ex[1] = origin[1] + spacing[1]*(dimension[1]-1); return ex; } public void createMapping(){ nm = new PolynominalMapping(); } /** * maps str to value at zValues[zId], overrides z value ad zId with mappingId, resulting from mapping String value * ensure that there is an instantiated mapping or create a new one with createMapping() * @param zId * @param str */ public void mapValueAt(int zId, String str){ zValues[zId] = nm.mapString(str); } public NominalMapping getMapping(){ return nm; } public boolean hasMapping(){ if (nm == null) return false; return true; } /** * fast interpolation according to the description in the R function interp.surface * @param x * @param y * @return */ private double getInterpolatedValue(double x,double y) { int x1 = (int) x; int x2 = x1+1; int y1 = (int)y; int y2 = y1+1; double ex = (x-x1)/(x2-x1); double ey = (y-y1)/(y2-y1); double[] coeff = { (1-ex)*(1-ey), (1-ex)*ey, ex*(1-ey), ex*ey }; //val = (1-ex)*(1-ey)*getValueAtId(x1, y1) + (1-ex)*ey*getValueAtId(x1, y2) + ex*(1-ey)*getValueAtId(x2, y1) + ex*ey*getValueAtId(x2, y2); double val = (coeff[0]==0?0:coeff[0]*getValueAtId(x1, y1)) + (coeff[1]==0?0:coeff[1]*getValueAtId(x1, y2)) + (coeff[2]==0?0:coeff[2]*getValueAtId(x2, y1)) + (coeff[3]==0?0:coeff[3]*getValueAtId(x2, y2)); return val; // x = x-origin[0]; // y = y-origin[1]; // // get the surrounding gridPoints for the x and y value // int indexX = (int)(x / spacing[0]); // int indexY = (int)(y/spacing[1]); // // if(indexX >= dimension[0]-1 || indexY >= dimension[1]-1) // throw new IndexOutOfBoundsException("The value is outside the grid"); // // double x1 = indexX * spacing[0] ; // double x2 = x1 + spacing[0]; // double y1 = indexY * spacing[1]; // double y2 = y1 + spacing[1]; // // // double deltaX1 = x-x1; // double deltaX2 = x2-x; // // interpolating the x-direction // double val1 =(deltaX2/spacing[0])*getValueAtId(indexX, indexY) +(deltaX1/spacing[0])*getValueAtId(indexX+1,indexY) ; // double val2 = (deltaX2/spacing[0])*getValueAtId(indexY, indexY+1) + (deltaX1/spacing[0])*getValueAtId(indexX+1, indexY+1); // // return ((y2-y)/spacing[1])*val1 + ((y-y1)/spacing[1])*val2; } }