/*
* 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.math.BigDecimal;
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: SOMSilhouetteValue.java 3883 2010-11-02 17:13:23Z frank $
*/
public class SOMSilhouetteValue extends AbstractQualityMeasure {
private double mapSilhouetteValue;
private double[][] unitSilhouetteValues;
private double min, max;
public SOMSilhouetteValue(Layer layer, InputData data) {
super(layer, data);
boolean debug = false;
System.out.println("Start computing SOM silhouette");
mapQualityNames = new String[] { "silhouette" };
mapQualityDescriptions = new String[] { "Silhouette Value" };
unitQualityNames = new String[] { "silhouette" };
unitQualityDescriptions = new String[] { "Silhouette Value" };
int xSize = layer.getXSize();
int ySize = layer.getYSize();
this.max = 0;
this.min = 0;
this.unitSilhouetteValues = new double[xSize][ySize];
StdErrProgressWriter progressWriter = new StdErrProgressWriter(layer.getXSize() * layer.getYSize(),
"Calculating SOMSilhouetteValue 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);
// System.out.println("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) {
if (debug) {
System.out.println("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) {
e.printStackTrace();
}
if (debug) {
System.out.println("\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++) {
if (debug) {
System.out.println("Handling input: " + (i + 1) + " out of " + u.getNumberOfMappedInputs());
}
InputDatum thisDatum = this.data.getInputDatum(u.getMappedInputNames()[i]);
double avgDistanceWithinCluster = 0d;
if (debug) {
System.out.println("\t found within cluster neighbour");
}
try {
avgDistanceWithinCluster = new L1Metric().distance(u.getWeightVector(), thisDatum);
} catch (MetricException e1) {
e1.printStackTrace();
}
double minDist = Double.POSITIVE_INFINITY;
if (debug) {
System.out.println("closestUnit.numberOfINputs: " + closestUnit.getNumberOfMappedInputs());
}
try {
minDist = new L1Metric().distance(thisDatum.getVector().toArray(),
closestUnit.getWeightVector());
} catch (MetricException e) {
e.printStackTrace();
}
if (debug) {
System.out.println("\t found closest vector in cluster neighbour");
}
double max = 0;
if (avgDistanceWithinCluster > minDist) {
max = avgDistanceWithinCluster;
} else {
max = minDist;
}
if (debug) {
System.out.println("\t minDist - avgDistanceWithinCluster / max: " + minDist + " - "
+ avgDistanceWithinCluster + " / " + max);
}
tmpUnitSilhouetteValues[i] = (minDist - avgDistanceWithinCluster) / max;
}
double unitSumSilhouette = 0;
if (debug) {
System.out.println(tmpUnitSilhouetteValues.length);
}
for (double tmpUnitSilhouetteValue : tmpUnitSilhouetteValues) {
unitSumSilhouette += tmpUnitSilhouetteValue;
if (debug) {
System.out.println("\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++) {
BigDecimal bd = new BigDecimal(0);
if (Double.isNaN(this.unitSilhouetteValues[x][y])) {
NaNCount++;
} else {
bd = new BigDecimal(this.unitSilhouetteValues[x][y]);
bd = bd.setScale(50, BigDecimal.ROUND_UP);
sumSilhouette += this.unitSilhouetteValues[x][y];
}
// System.out.println("x / y " + x + " / " + y + " silVal: " + bd.doubleValue());
}
}
if (debug) {
System.out.println("sumSilhouette: " + sumSilhouette);
}
if (debug) {
System.out.println("NaNCount: " + NaNCount);
}
if (debug) {
System.out.println("#units: " + new Double(layer.getXSize() * layer.getYSize()).doubleValue());
}
if (debug) {
System.out.println("#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);
System.out.println("mapSilhouetteValue: " + this.mapSilhouetteValue);
}
@Override
public double getMapQuality(String name) throws QualityMeasureNotFoundException {
if (name.equals("somSilhouettevalue")) {
return this.mapSilhouetteValue;
} else {
throw new QualityMeasureNotFoundException("Quality measure named " + name + " not found.");
}
}
@Override
public double[][] getUnitQualities(String name) throws QualityMeasureNotFoundException {
return this.unitSilhouetteValues;
}
public void findMaxMin() {
this.max = Double.NEGATIVE_INFINITY;
this.min = Double.POSITIVE_INFINITY;
for (int y = 0; y < layer.getYSize(); y++) {
for (int x = 0; x < layer.getXSize(); x++) {
if (this.unitSilhouetteValues[x][y] > this.max) {
this.max = this.unitSilhouetteValues[x][y];
}
if (this.unitSilhouetteValues[x][y] < this.min) {
this.min = this.unitSilhouetteValues[x][y];
}
}
}
}
public double getMax() {
if (this.max == 0) {
this.findMaxMin();
}
return this.max;
}
public double getMin() {
if (this.min == 0) {
this.findMaxMin();
}
return this.min;
}
}