/* * 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.ArrayList; import java.util.Hashtable; import at.tuwien.ifs.somtoolbox.data.InputData; import at.tuwien.ifs.somtoolbox.layers.GrowingLayer; 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.DistanceMetric; import at.tuwien.ifs.somtoolbox.layers.metrics.MetricException; import at.tuwien.ifs.somtoolbox.util.comparables.UnitDistance; /** * Implementation of Intrinsic Distance Quality * * @author Gerd Platzgummer * @version $Id: IntrinsicDistance.java 3883 2010-11-02 17:13:23Z frank $ */ public class IntrinsicDistance extends AbstractQualityMeasure { double[] _SampleSummand2 = null; double[][] UnitSummand1; double[][] UnitSummand2; double[][] Unit_ID; double MapSummand1; double Map_ID = 0.0; public IntrinsicDistance(Layer layer, InputData data) { super(layer, data); int xSize1 = layer.getXSize(); int ySize1 = layer.getYSize(); UnitSummand1 = new double[xSize1][ySize1]; UnitSummand2 = new double[xSize1][ySize1]; Unit_ID = new double[xSize1][ySize1]; for (int x = 0; x < xSize1; x++) { for (int y = 0; y < ySize1; y++) { UnitSummand1[x][y] = 0.0; // Summand 1: enthaelt Distanz eines jeden Samples zu seiner BMU, gemappt auf // die Unit UnitSummand2[x][y] = 0.0; // Summand 2: Distanz von BMU (eines Samples) zu 2nd ueber Dijkstra, gemappt // auf die Unit } } MapSummand1 = 0; /** *********Summand 1: Aequivalent zum (einfachen) Quantization Error */ int nonEmpty = 0; for (int y = 0; y < layer.getYSize(); y++) { for (int x = 0; x < layer.getXSize(); x++) { double quantErr = 0; Unit u = null; try { u = layer.getUnit(x, y); } catch (LayerAccessException e) { // TODO: this does not happen } double[] dists = u.getMappedInputDistances(); for (int i = 0; i < u.getNumberOfMappedInputs(); i++) { quantErr += dists[i]; } UnitSummand1[x][y] = quantErr; if (u.getNumberOfMappedInputs() > 0) { nonEmpty++; } } // MapSummand1 += UnitSummand1[x][y]; } /** *********Summand 2: Dist BMU 2ndBMU ueber den shortest path */ Unit[] V = ((GrowingLayer) layer).getAllUnits(); int xSize = layer.getXSize(); int ySize = layer.getYSize(); int unitcount = xSize * ySize; int samplecount = data.numVectors(); Hashtable<Unit, UnitInfo> units = new Hashtable<Unit, UnitInfo>(); DistanceMetric metric = layer.getMetric(); try { for (int i = 0; i < unitcount; i++) // 4 Nachbarunits bestimmen, Distanzen dazu { units.put(V[i], new UnitInfo(V[i])); QuadUnitDistance quad = new QuadUnitDistance(); for (int p = 0; p < 4; p++) { Unit neigh4 = null; if (p == 0 && V[i].getXPos() > 0) { neigh4 = layer.getUnit(V[i].getXPos() - 1, V[i].getYPos()); } else if (p == 1 && V[i].getYPos() > 0) { neigh4 = layer.getUnit(V[i].getXPos(), V[i].getYPos() - 1); } else if (p == 2 && V[i].getXPos() < xSize - 1) { neigh4 = layer.getUnit(V[i].getXPos() + 1, V[i].getYPos()); } else if (p == 3 && V[i].getYPos() < ySize - 1) { neigh4 = layer.getUnit(V[i].getXPos(), V[i].getYPos() + 1); } if (neigh4 != null) { UnitDistance ud = new UnitDistance(neigh4, metric.distance(V[i].getWeightVector(), neigh4.getWeightVector())); quad.putUnitDistance(p, ud); } } units.get(V[i]).setQuad(quad); // die 2-4 nachbarn und die jeweilige distanz } } catch (LayerAccessException ex) { } catch (MetricException mex) { } _SampleSummand2 = new double[samplecount]; for (int s = 0; s < samplecount; s++) { Unit[] winners = ((GrowingLayer) layer).getWinners(data.getInputDatum(s), 2); Unit bmu = winners[0]; Unit sbmu = winners[1]; for (int u = 0; u < unitcount; u++) { UnitInfo ui = units.get(V[u]); ui.setPredecessor(null); ui.setDistance(Double.MAX_VALUE); // alle distances auf unendlich initialisieren } units.get(bmu).setDistance(0.0); // Shortest path zwischen der bmu und sbmu Dijkstra(V, unitcount, bmu, sbmu, units); _SampleSummand2[s] = units.get(sbmu).getDistance(); UnitSummand2[bmu.getXPos()][bmu.getYPos()] += _SampleSummand2[s]; } /* hier noch den _SampleSummand2[s] auf die jeweilige Unit mappen */ // UnitSummand2[bmu.getXPos()][bmu.getYPos()]++; for (int x = 0; x < xSize1; x++) { for (int y = 0; y < ySize1; y++) { Unit_ID[x][y] = UnitSummand1[x][y] + UnitSummand2[x][y]; Map_ID += Unit_ID[x][y]; } } Map_ID = Map_ID / samplecount; // oder nonEmpty: Units mit assoziierten Samples } private void Dijkstra(Unit[] V, int unitcount, Unit bmu, Unit sbmu, Hashtable<Unit, UnitInfo> units) { ArrayList<Unit> s = new ArrayList<Unit>(); s.add(bmu); // relax bmu QuadUnitDistance q = units.get(bmu).getQuad(); for (int i = 0; i < 4; i++) { UnitDistance ud = q.getUnitDistance(i); if (ud != null) { Relax(units.get(bmu), units.get(ud.getUnit()), ud.getDistance()); } } while (true) { // naechste Unit laut distances, die nicht schon in S ist, heraussuchen double mindistance = Double.MAX_VALUE; Unit minunit = null; for (int i = 0; i < unitcount; i++) { if (!s.contains(V[i]) && units.get(V[i]).getDistance() < mindistance) { mindistance = units.get(V[i]).getDistance(); minunit = V[i]; } } s.add(minunit); // relax minunit QuadUnitDistance q1 = units.get(minunit).getQuad(); for (int i = 0; i < 4; i++) { UnitDistance ud1 = q1.getUnitDistance(i); if (ud1 != null) { Relax(units.get(minunit), units.get(ud1.getUnit()), ud1.getDistance()); } } // abbruch? if (minunit == sbmu) { break; } } } private void Relax(UnitInfo u, UnitInfo v, double distance) { if (v.getDistance() > u.getDistance() + distance) { v.setDistance(u.getDistance() + distance); v.setPredecessor(u.getUnit()); } } public class QuadUnitDistance { UnitDistance[] unitDistances = new UnitDistance[4]; // {null, null, null, null}; public QuadUnitDistance() { } public UnitDistance getUnitDistance(int index) { return unitDistances[index]; } public void putUnitDistance(int index, UnitDistance ud) { unitDistances[index] = ud; } } public class UnitInfo { Unit unit; double distance = 0.0; Unit predecessor = null; QuadUnitDistance quadUnitDistance = null; public UnitInfo(Unit u) { unit = u; } public Unit getUnit() { return unit; } public double getDistance() { return distance; } public void setDistance(double d) { distance = d; } public Unit getPredecessor() { return predecessor; } public void setPredecessor(Unit pre) { predecessor = pre; } public QuadUnitDistance getQuad() { return quadUnitDistance; } public void setQuad(QuadUnitDistance quad) { quadUnitDistance = quad; } } /** *********************************************************************************************************** */ /* * Ausgabe: ID_Sample-(nicht ID_Unit!)- Werte, Durchschnitt */ @Override public double getMapQuality(String name) throws QualityMeasureNotFoundException { if (name.equals("ID_Map")) { return Map_ID; } else { throw new QualityMeasureNotFoundException("Quality measure with name " + name + " not found."); } } /* * Ausgabe: ID_Sample- Werte, Mapping auf die entsprechende Unit */ @Override public double[][] getUnitQualities(String name) throws QualityMeasureNotFoundException { if (name.equals("ID_Unit")) { return Unit_ID; } else { throw new QualityMeasureNotFoundException("Quality measure with name " + name + " not found."); } } }