/* * Copyright 2004-2010 Information & Software Engineering Group (188/1) * Institute of Software Technology and Interactive Systems * Vienna University of Technology, Austria * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.tuwien.ifs.somtoolbox.visualization; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.logging.Logger; import cern.colt.matrix.DoubleFactory2D; import cern.colt.matrix.DoubleMatrix2D; import at.tuwien.ifs.somtoolbox.SOMToolboxException; import at.tuwien.ifs.somtoolbox.data.AbstractSOMLibSparseInputData; import at.tuwien.ifs.somtoolbox.data.InputDatum; import at.tuwien.ifs.somtoolbox.data.SOMVisualisationData; import at.tuwien.ifs.somtoolbox.layers.GrowingLayer; import at.tuwien.ifs.somtoolbox.layers.LayerAccessException; import at.tuwien.ifs.somtoolbox.layers.Unit; import at.tuwien.ifs.somtoolbox.layers.metrics.DistanceMetric; import at.tuwien.ifs.somtoolbox.layers.metrics.MetricException; import at.tuwien.ifs.somtoolbox.models.GrowingSOM; import at.tuwien.ifs.somtoolbox.util.VectorTools; /** * This Visualizer provides the Gap visualiser, as described in <i><b>Samuel Kaski, Janne Nikkilä, and Teuvo * Kohonen.</b> Methods for exploratory cluster analysis. In Proceedings of the International Conference on Advances in * Infrastructure for Electronic Business, Science, and Education on the Internet, L'Aquila, July 31–August 6. Scuola * Superiore G. Reiss Romoli, 2000, L'Aquila, July 31-August 6. ISBN 88-85280-52-8</i> * * @author Rudolf Mayer * @version $Id: GapVisualiser.java 3869 2010-10-21 15:56:09Z mayer $ */ public class GapVisualiser extends UMatrix { public double dataPercentage = 0.8d; public double neighbourHood = 0.1d; public GapVisualiser() { NUM_VISUALIZATIONS = 1; VISUALIZATION_NAMES = new String[] { "Gap-Matrix" }; VISUALIZATION_SHORT_NAMES = new String[] { "Gap" }; VISUALIZATION_DESCRIPTIONS = new String[] { "Implementation of the Gap visualisation as described in \"Samuel Kaski, Janne Nikkilä, and Teuvo Kohonen\n" + "Methods for exploratory cluster analysis. In Proceedings of SSGRR 2000.\"" }; setInterpolate(false); // by default, the Gap-Matrix is not interpolated neededInputObjects = new String[] { SOMVisualisationData.INPUT_VECTOR }; } @Override public BufferedImage createVisualization(int index, GrowingSOM gsom, int width, int height) throws SOMToolboxException { checkVariantIndex(index, getClass()); return createGapMatrix(gsom, width, height); } private BufferedImage createGapMatrix(GrowingSOM gsom, int width, int height) throws SOMToolboxException { AbstractSOMLibSparseInputData inputData = (AbstractSOMLibSparseInputData) gsom.getSharedInputObjects().getInputData(); GrowingLayer layer = gsom.getLayer(); DistanceMetric metric = layer.getMetric(); int umatW = layer.getXSize() * 2 - 1; int umatH = layer.getYSize() * 2 - 1; try { double[][][] g = new double[layer.getXSize()][layer.getYSize()][]; for (int row = 0; row < layer.getYSize(); row++) { for (int col = 0; col < layer.getXSize(); col++) { final double[] m_i = layer.getUnit(col, row).getWeightVector(); // find all the name of the inputs mapped to the neighbouring units ArrayList<String> mappedItems = new ArrayList<String>(); // consider a radius of 1.5, which means an 8-unit neighbourhood final ArrayList<Unit> neighbouringUnits = layer.getNeighbouringUnits(col, row, 1.5); for (Unit unit : neighbouringUnits) { mappedItems.addAll(unit.getMappedInputNamesAsList()); } // retrieve the inputs to the names, and sort them by their distance to the model vector InputDatum[] nearestN = inputData.getByNameDistanceSorted(m_i, mappedItems, metric); // take 80% of those int cut = (int) Math.round(nearestN.length * dataPercentage); double[][] vectors = new double[cut][]; for (int i = 0; i < vectors.length; i++) { vectors[i] = nearestN[i].getVector().toArray(); } double[] c_i; if (vectors.length > 0) { c_i = VectorTools.meanVector(vectors); // Equation (5) } else { c_i = m_i; } g[col][row] = VectorTools.subtract(m_i, c_i); // Equation (4) } } // System.out.println(ArrayUtils.toString(g)); // System.out.println(StringUtils.toString(g)); DoubleMatrix2D matrix = DoubleFactory2D.dense.make(umatH, umatW, -1); boolean first = true; // calc horizontal, vertical and diagonal distances between units if (first) { for (int row = 0; row < layer.getYSize(); row++) { for (int col = 0; col < layer.getXSize(); col++) { try { double[] g_i = g[col][row]; if (col + 1 < layer.getXSize()) { // rightwards matrix.set(row * 2, col * 2 + 1, metric.distance(g_i, g[col + 1][row])); if (row + 1 < layer.getYSize()) { // right-downwards matrix.set(row * 2 + 1, col * 2 + 1, metric.distance(g_i, g[col + 1][row + 1])); } } if (row + 1 < layer.getYSize()) { // downwards matrix.set(row * 2 + 1, col * 2, metric.distance(g_i, g[col][row + 1])); } } catch (MetricException me) { Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(me.getMessage()); System.exit(-1); } } } } else { for (int row = 0; row < umatH; row++) { for (int col = 0; col < umatW; col++) { try { int x = (col - 1) / 2; if (col % 2 != 0 && row % 2 == 0) { // horizontal matrix.set(row, col, metric.distance(g[x][row / 2], g[x + 1][row / 2])); } else { int y = (row - 1) / 2; if (col % 2 == 0 && row % 2 != 0) { // vertical matrix.set(row, col, metric.distance(g[col / 2][y], g[col / 2][y + 1])); } else if (col % 2 != 0 && row % 2 != 0) { // diagonal double d1 = metric.distance(g[x][y], g[x + 1][y + 1]); double d2 = metric.distance(g[x][y + 1], g[x + 1][y]); matrix.set(row, col, (d1 + d2) / (2 * Math.sqrt(2))); } } } catch (MetricException me) { Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(me.getMessage()); System.exit(-1); } } } } // System.out.println(matrix); // interpolate based on surrounding distances between units (median) for (int row = 0; row < umatH; row += 2) { for (int col = 0; col < umatW; col += 2) { if (row == 0 && col == 0) { // upper left unit matrix.set(row, col, VectorTools.median(matrix.get(row + 1, col), matrix.get(row, col + 1))); } else if (col == umatW - 1 && row == 0) { // upper right unit matrix.set(row, col, VectorTools.median(matrix.get(row, col - 1), matrix.get(row + 1, col))); } else if (col == 0 && row == umatH - 1) { // lower left unit matrix.set(row, col, VectorTools.median(matrix.get(row, col + 1), matrix.get(row - 1, col))); } else if (col == umatW - 1 && row == umatH - 1) { // lower right unit matrix.set(row, col, VectorTools.median(matrix.get(row, col - 1), matrix.get(row - 1, col))); } else if (col == 0) { // left border matrix.set(row, col, VectorTools.median(matrix.get(row - 1, col), matrix.get(row + 1, col), matrix.get(row, col + 1))); } else if (col == umatW - 1) { // right border matrix.set(row, col, VectorTools.median(matrix.get(row - 1, col), matrix.get(row + 1, col), matrix.get(row, col - 1))); } else if (row == 0) { // top border matrix.set(row, col, VectorTools.median(matrix.get(row, col - 1), matrix.get(row, col + 1), matrix.get(row + 1, col))); } else if (row == umatH - 1) { // bottom border matrix.set(row, col, VectorTools.median(matrix.get(row, col - 1), matrix.get(row, col + 1), matrix.get(row - 1, col))); } else { // middle unit matrix.set(row, col, VectorTools.median(matrix.get(row, col - 1), matrix.get(row, col + 1), matrix.get(row - 1, col), matrix.get(row + 1, col))); } } } VectorTools.normalise(matrix); return createImage(gsom, matrix, width, height, interpolate); } catch (LayerAccessException e) { e.printStackTrace(); return null; } } }