/* * 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.layers.quality; import java.util.logging.Logger; import at.tuwien.ifs.somtoolbox.data.InputData; import at.tuwien.ifs.somtoolbox.data.InputDatum; import at.tuwien.ifs.somtoolbox.layers.Layer; import at.tuwien.ifs.somtoolbox.layers.LayerAccessException; import at.tuwien.ifs.somtoolbox.layers.Unit; import at.tuwien.ifs.somtoolbox.layers.metrics.L1Metric; import at.tuwien.ifs.somtoolbox.layers.metrics.MetricException; import at.tuwien.ifs.somtoolbox.util.StdErrProgressWriter; /** * @author Robert Neumayer * @version $Id: PseudoSilhouetteValue.java 3883 2010-11-02 17:13:23Z frank $ */ public class PseudoSilhouetteValue extends AbstractQualityMeasure { private double mapSilhouetteValue; private double[][] unitSilhouetteValues; Logger logger = Logger.getLogger("at.tuwien.ifs.somtoolbox"); public PseudoSilhouetteValue(Layer layer, InputData data) { super(layer, data); logger.info("Start computing silhouette"); mapQualityNames = new String[] { "pseudoSilhouette" }; mapQualityDescriptions = new String[] { "Pseudo Silhouette Value" }; unitQualityNames = new String[] { "pseudoSilhouette" }; unitQualityDescriptions = new String[] { "Pseudo Silhouette Value" }; int xSize = layer.getXSize(); int ySize = layer.getYSize(); this.unitSilhouetteValues = new double[xSize][ySize]; StdErrProgressWriter progressWriter = new StdErrProgressWriter(layer.getXSize() * layer.getYSize(), "Calculating PseudoSilhouetteValue for unit ", 50); for (int y = 0; y < layer.getYSize(); y++) { for (int x = 0; x < layer.getXSize(); x++) { progressWriter.progress(y * layer.getYSize() + x); // logger.fine("handling unit: " + (x + 1) + " / " + (y + 1) + " of " + (layer.getXSize() * // layer.getYSize())); Unit u = null; try { u = layer.getUnit(x, y); } catch (LayerAccessException e) { // TODO: this does not happen } // added to deal with mnemonic (sparse) SOMs if (u != null) { // find closest unit to that one double minUnitDistance = Double.POSITIVE_INFINITY; int xxx = 0; int yyy = 0; for (int yy = 0; yy < layer.getYSize(); yy++) { for (int xx = 0; xx < layer.getXSize(); xx++) { Unit closestUnit = null; try { closestUnit = layer.getUnit(xx, yy); } catch (LayerAccessException e) { // TODO: this does not happen } // do not compare it to itself if (!(xx == x && yy == y) && closestUnit.getNumberOfMappedInputs() > 0) { logger.finer("xx / yy || x / y " + xx + " / " + yy + " || " + x + " / " + y); try { // assign value if smaller double distance = new L1Metric().distance(u.getWeightVector(), closestUnit.getWeightVector()); if (distance < minUnitDistance) { minUnitDistance = distance; xxx = xx; yyy = yy; } } catch (MetricException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } // get b(i) out of other unit Unit closestUnit = null; try { closestUnit = layer.getUnit(xxx, yyy); } catch (LayerAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } logger.finer("\t found closest unit " + (xxx + 1) + " / " + (yyy + 1)); double[] tmpUnitSilhouetteValues = new double[u.getNumberOfMappedInputs()]; // for each mapped datum for (int i = 0; i < u.getNumberOfMappedInputs(); i++) { logger.finer("Handling input: " + (i + 1) + " out of " + u.getNumberOfMappedInputs()); InputDatum thisDatum = this.data.getInputDatum(u.getMappedInputNames()[i]); double distancesWithinCluster = 0; // again for each mapped datum for (int j = 0; j < u.getNumberOfMappedInputs(); j++) { // compare to each other // not to itself though if (i == j) { continue; } InputDatum thatDatum; thatDatum = this.data.getInputDatum(u.getMappedInputNames()[j]); try { double withinDistance = new L1Metric().distance(thisDatum.getVector().toArray(), thatDatum.getVector().toArray()); distancesWithinCluster += withinDistance; logger.finest("distances within: " + withinDistance); } catch (MetricException e) { // TODO Auto-generated catch block e.printStackTrace(); } } double avgDistanceWithinCluster; if (u.getNumberOfMappedInputs() == 1) { avgDistanceWithinCluster = 0d; } else { avgDistanceWithinCluster = distancesWithinCluster / (u.getNumberOfMappedInputs() - 1); } logger.finer("\t found within cluster neighbour"); double minDist = Double.POSITIVE_INFINITY; logger.finer("closestUnit.numberOfINputs: " + closestUnit.getNumberOfMappedInputs()); try { minDist = new L1Metric().distance(thisDatum.getVector().toArray(), closestUnit.getWeightVector()); } catch (MetricException e) { // TODO Auto-generated catch block e.printStackTrace(); } logger.finer("\t found closest vector in cluster neighbour"); // there we go b(i) double max = 0; if (avgDistanceWithinCluster > minDist) { max = avgDistanceWithinCluster; } else { max = minDist; } logger.finer("\t minDist - avgDistanceWithinCluster / max: " + minDist + " - " + avgDistanceWithinCluster + " / " + max); tmpUnitSilhouetteValues[i] = (minDist - avgDistanceWithinCluster) / max; } double unitSumSilhouette = 0; logger.finer(String.valueOf(tmpUnitSilhouetteValues.length)); for (double tmpUnitSilhouetteValue : tmpUnitSilhouetteValues) { unitSumSilhouette += tmpUnitSilhouetteValue; logger.finer("\t" + tmpUnitSilhouetteValue); } this.unitSilhouetteValues[x][y] = unitSumSilhouette / new Double(tmpUnitSilhouetteValues.length).doubleValue(); } } } double sumSilhouette = 0; int NaNCount = 0; for (int y = 0; y < layer.getYSize(); y++) { for (int x = 0; x < layer.getXSize(); x++) { // logger.finer("x / y " + x + " / " + y + " silVal: " + this.unitSilhouetteValues[x][y]); if (Double.isNaN(this.unitSilhouetteValues[x][y])) { NaNCount++; } else { sumSilhouette += this.unitSilhouetteValues[x][y]; } } } logger.finer("sumSilhouette: " + sumSilhouette); logger.finer("NaNCount: " + NaNCount); logger.finer("#units: " + new Double(layer.getXSize() * layer.getYSize()).doubleValue()); logger.finer("#units - NaNCount: " + (new Double(layer.getXSize() * layer.getYSize()).doubleValue() - NaNCount)); // get closest unit // get lowest distance in that cluster this.mapSilhouetteValue = sumSilhouette / (new Double(layer.getXSize() * layer.getYSize()).doubleValue() - NaNCount); logger.finer("mapSilhouetteValue: " + this.mapSilhouetteValue); } @Override public double getMapQuality(String name) throws QualityMeasureNotFoundException { if (name.equals("pseudoSilhouettevalue")) { return this.mapSilhouetteValue; } else { throw new QualityMeasureNotFoundException("Quality measure named " + name + " not found."); } } @Override public double[][] getUnitQualities(String name) throws QualityMeasureNotFoundException { return this.unitSilhouetteValues; } }