/*
* 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.Arrays;
import java.util.Random;
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.Unit;
import at.tuwien.ifs.somtoolbox.layers.metrics.DistanceMetric;
/**
* Implementation of Topographic Product Quality Measure.<br>
* More Infos: H.U. Bauer and K.R. Pawelzik. Quantifying the neighborhood preservation of self- organizing feature maps.
* In IEEE Transactions on Neural Networks 3, pages 570-579, 1992.
*
* @author Gerd Platzgummer
* @version $Id: TopographicProduct.java 3883 2010-11-02 17:13:23Z frank $
*/
public class TopographicProduct extends AbstractQualityMeasure {
DistanceMetric metric = null;
double _K = 0;
DistanceTag[][][] protoDist = null;
DistanceTag[][][] mapDist = null;
double[][] _Q1Q2temp = null; // Formel 16 im Bauer-Paper; Tempor�rer TP Wert f�r 1 bestimmtes k w�hrend Iteration
double[][] tpUnitValues = null;
public TopographicProduct(Layer layer, InputData data) {
super(layer, data);
metric = layer.getMetric();
int xSize = layer.getXSize();
int ySize = layer.getYSize();
mapDist = new DistanceTag[xSize][ySize][xSize * ySize];
protoDist = new DistanceTag[xSize][ySize][xSize * ySize];
tpUnitValues = new double[xSize][ySize];
}
private void resetResults() {
for (int x = 0; x < layer.getXSize(); x++) {
for (int y = 0; y < layer.getYSize(); y++) {
tpUnitValues[x][y] = 1.0;
}
}
}
private void rankOutputSpace() {
try {
int xSize = layer.getXSize();
int ySize = layer.getYSize();
DistanceTagComparator comparator = new DistanceTagComparator();
System.out.println("xSize " + xSize + " ySize " + ySize);
for (int x = 0; x < xSize; x++) {
for (int y = 0; y < ySize; y++) {
System.out.println("output x " + x + " y " + y);
for (int x2 = 0; x2 < xSize; x2++) {
for (int y2 = 0; y2 < ySize; y2++) {
// System.out.println("x " + x + " y " + y + " x2 " + x2 + " y2 " + y2);
double distance = Double.MAX_VALUE;
if (x != x2 || y != y2) {
distance = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
}
mapDist[x][y][x2 * ySize + y2] = new DistanceTag(x2, y2, distance);
}
}
// System.out.println("vor sort");
Arrays.sort(mapDist[x][y], comparator);
// QuickSort.sort(mapDist[x][y], comparator);
// rank it 2006 (rankt den Output space)
double curdist = 1;
int currank = 1;
for (int z = 0; z < xSize * ySize; z++) {
if (mapDist[x][y][z].getDistance() != curdist) {
curdist = mapDist[x][y][z].getDistance();
currank = z + 1;
}
mapDist[x][y][z].setRank(currank);
}
}
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
private void rankInputSpace() {
try {
int xSize = layer.getXSize();
int ySize = layer.getYSize();
DistanceTagComparator comparator = new DistanceTagComparator();
for (int x = 0; x < xSize; x++) {
for (int y = 0; y < ySize; y++) {
System.out.println("input x " + x + " y " + y);
for (int x2 = 0; x2 < xSize; x2++) {
for (int y2 = 0; y2 < ySize; y2++) {
double distance = Double.MAX_VALUE;
if (x != x2 || y != y2) {
distance = metric.distance(((GrowingLayer) layer).getUnit(x, y).getWeightVector(),
((GrowingLayer) layer).getUnit(x2, y2).getWeightVector());
}
protoDist[x][y][x2 * ySize + y2] = new DistanceTag(x2, y2, distance);
}
}
// System.out.println("vor input sort");
Arrays.sort(protoDist[x][y], comparator);
// QuickSort.sort(protoDist[x][y], comparator);
// rank it 2006 (rankt den Input space)
double curdist = -1;
int currank = 0;
for (int z = 0; z < xSize * ySize; z++) {
if (protoDist[x][y][z].getDistance() != curdist) {
curdist = protoDist[x][y][z].getDistance();
currank = z + 1;
}
protoDist[x][y][z].setRank(currank);
}
}
}
} catch (Exception ex) {
System.out.println("ho " + ex.getMessage());
}
}
private void calculateTP() {
for (int x = 0; x < layer.getXSize(); x++) {
for (int y = 0; y < layer.getYSize(); y++) {
for (int k = 0; k < _K; k++) {
tpUnitValues[x][y] = tpUnitValues[x][y] * calcQ1(x, y, k) * calcQ2(x, y, k);
}
tpUnitValues[x][y] = Math.pow(tpUnitValues[x][y], 1 / (2 * _K));
}
}
}
private double calculateTPMap() {
int kmax = layer.getXSize() * layer.getYSize() - 1;
double tpmap = 0.0;
for (int k = 1; k <= kmax; k++) {
System.out.println("MAP: k " + k);
resetResults();
_K = k;
calculateTP();
DebugDoubles("calculateTPMap3");
for (int x = 0; x < layer.getXSize(); x++) {
for (int y = 0; y < layer.getYSize(); y++) {
tpmap += Math.log(tpUnitValues[x][y]);
}
}
System.out.println(tpmap);
}
tpmap = tpmap * 1 / (kmax * (kmax + 1.0));
return tpmap;
}
private void DebugDoubles(String loc) {
// System.out.println("DebugDoubles in " + loc);
// System.out.println("_K=" + _K);
// for (int x = 11; x < layer.getXSize(); x++) {
// for (int y = 3; y < layer.getYSize(); y++) {
// System.out.println("X=" + x + " Y=" + y + " _TPU=" + tpUnitValues[x][y]);
// }
// }
}
private int GetRandomIndex(DistanceTag[] dtags, int chosen) {
double rank = dtags[chosen].getRank();
int minindex = chosen;
for (int i = minindex; i >= 0; i--) {
if (dtags[i].getRank() != rank) {
minindex = i + 1;
break;
}
}
int maxindex = chosen;
for (int i = maxindex; i < dtags.length; i++) {
if (dtags[i].getRank() != rank) {
maxindex = i - 1;
break;
}
}
Random rand = new Random();
return rand.nextInt(maxindex - minindex + 1) + minindex;
}
private double calcQ1(int x, int y, int k) {
try {
double[] curProto = layer.getUnit(x, y).getWeightVector(); // Protoyp der aktuellen Unit
// System.out.println("q1 a");
int random = GetRandomIndex(mapDist[x][y], k);
DistanceTag kNextDistanceTag = mapDist[x][y][random];
Unit kNextUnit = layer.getUnit(kNextDistanceTag.getX(), kNextDistanceTag.getY());// Koordinaten zu k
// n�chster Unit ermitteln
double[] kNextProto = kNextUnit.getWeightVector();
double q1Dividend = metric.distance(curProto, kNextProto);
double q1Divisor = protoDist[x][y][k].getDistance();
return q1Dividend / q1Divisor;
} catch (Exception ex) {
System.out.println(ex.getMessage());
return 0.0;
}
}
private double calcQ2(int x, int y, int k) {
try {
int random = GetRandomIndex(mapDist[x][y], k);
double q2Dividend = mapDist[x][y][random].getDistance();
DistanceTag kNextDistanceTag = protoDist[x][y][k];
double q2Divisor = Math.sqrt((kNextDistanceTag.getX() - x) * (kNextDistanceTag.getX() - x)
+ (kNextDistanceTag.getY() - y) * (kNextDistanceTag.getY() - y));
return q2Dividend / q2Divisor;
} catch (Exception ex) {
System.out.println(ex.getMessage());
return 0.0;
}
}
/**
* @see at.tuwien.ifs.somtoolbox.layers.quality.QualityMeasure#getMapQuality(java.lang.String)
*/
@Override
public double getMapQuality(String name) throws QualityMeasureNotFoundException {
if (name.equals("TP_Map")) {
resetResults();
rankInputSpace();
rankOutputSpace();
return calculateTPMap();
} else {
throw new QualityMeasureNotFoundException("Quality measure with name " + name + " not found.");
}
}
/**
* @see at.tuwien.ifs.somtoolbox.layers.quality.QualityMeasure#getUnitQualities(java.lang.String)
*/
@Override
public double[][] getUnitQualities(String name) throws QualityMeasureNotFoundException {
if (name.startsWith("TP_Unit|")) {
int k = Integer.valueOf(name.substring(8)).intValue();
// Berechnung wird hier gestartet; Caching: wenn gleiches k schon ein Ergebnis vorhanden, dann dieses
// zur�ckgeben, sonst Neuberechnung
if (_K != k) {
resetResults();
rankInputSpace();
rankOutputSpace();
_K = k;
calculateTP();
}
return tpUnitValues;
} else {
throw new QualityMeasureNotFoundException("Quality measure with name " + name + " not found.");
}
}
/** *********************************************************************************************************** */
/** *********************************************************************************************************** */
public class DistanceTag {
int x;
int y;
double distance = 0.0;
double rank = 0.0;
public DistanceTag(int x, int y) {
this.x = x;
this.y = y;
}
public DistanceTag(int x, int y, double distance) {
this(x, y);
this.distance = distance;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public double getDistance() {
return distance;
}
public void setDistance(double d) {
distance = d;
}
public double getRank() {
return rank;
}
public void setRank(double r) {
rank = r;
}
}
public class DistanceTagComparator implements java.util.Comparator<DistanceTag> {
@Override
public int compare(DistanceTag t1, DistanceTag t2) {
double diff = t1.getDistance() - t2.getDistance();
if (diff > 0.0) {
return 1;
} else if (diff < 0.0) {
return -1;
} else {
return 0;
}
}
}
}