/* * 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.Vector; 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; /** * Implementation of Topographic Function Quality Measure<br> * More Infos: T. Villmann, R. Der, M. Herrmann, and T.M. Martinez. Topology preservation in self- organizing feature * maps: Exact definition and measurement.In IEEE Transactions on Neural Networks 8, pages 256-266, 1997. * * @author Gerd Platzgummer * @version $Id: TopographicFunction.java 3590 2010-05-21 10:43:45Z mayer $ */ public class TopographicFunction { Layer layer = null; InputData data = null; public TopographicFunction(Layer layer, InputData data) { this.layer = layer; this.data = data; } /** * @see at.tuwien.ifs.somtoolbox.layers.quality.QualityMeasure#getUnitQualities(java.lang.String) */ public double[] getFunctionValues(int K) { int xsize = layer.getXSize(); int ysize = layer.getYSize(); // TEST // xsize = 2; // ysize = 2; // TEST ENDE // N = Total number of units int N = xsize * ysize; // initialize adjacency matrix int[][] adj = new int[N][N]; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { adj[i][j] = Integer.MAX_VALUE; } } // build adjacency matrix for (int s = 0; s < data.numVectors(); s++) { Unit[] winners = ((GrowingLayer) layer).getWinners(data.getInputDatum(s), 2); Unit bmu = winners[0]; Unit sbmu = winners[1]; int xposn = xsize * bmu.getYPos() + bmu.getXPos(); int yposn = xsize * sbmu.getYPos() + sbmu.getXPos(); if (xposn > yposn) {// triangular adjacency matrix adj[xposn][yposn] = 1; } else { adj[yposn][xposn] = 1; } } for (int zeile = 0; zeile < N; zeile++) {// jeden Start-Knoten durchgehen for (int spalte = zeile + 1; spalte < N; spalte++) {// jeden Ziel-Knoten durchgehen if (adj[spalte][zeile] != 1) { // erreichbare Knoten ermitteln Vector<Integer> erreichbaren = new Vector<Integer>(); for (int i = 0; i < N; i++) { if (i != zeile) {// adj[i][zeile] fuer i==zeile ist immer Integer.MAX_VALUE, daher unwichtig int d = Integer.MAX_VALUE; if (i < zeile) {// Dreiecksmatrix d = adj[zeile][i]; } else { d = adj[i][zeile]; } if (d < Integer.MAX_VALUE) { erreichbaren.add(new Integer(i)); } } } while (!erreichbaren.isEmpty()) { // naehesten erreichbaren Knoten ermitteln int min = Integer.MAX_VALUE; int minpos = -1; int minvpos = -1; for (int i = 0; i < erreichbaren.size(); i++) { int minposcand = erreichbaren.get(i).intValue(); int mincand = -1; if (minposcand < zeile) { // Dreiecksmatrix mincand = adj[zeile][minposcand]; } else { mincand = adj[minposcand][zeile]; } if (mincand < min) { min = mincand; minpos = minposcand; minvpos = i; } } if (minpos != -1) {// muss immer true sein erreichbaren.remove(minvpos); // naehesten aus dem Vector der Erreichbaren entfernen if (minpos == spalte) {// wenn der Naechste schon der Zielknoten ist break; // dann hoeren wir auf, es gibt keinen naeheren Weg } else {// relax // wir suchen alle Knoten, die von minpos aus erreichbar sind for (int i = 0; i < N; i++) { if (i != minpos && i != zeile) { // adj[i][minpos] fuer i==minpos ist immer // Integer.MAX_VALUE, daher // unwichtig int d = Integer.MAX_VALUE; if (i < minpos) {// Dreiecksmatrix d = adj[minpos][i]; } else { d = adj[i][minpos]; } if (d < Integer.MAX_VALUE) { // also erreichbar if (i < zeile) {// Dreiecksmatrix if (d + min < adj[zeile][i]) { adj[zeile][i] = d + min; } } else { if (d + min < adj[i][zeile]) { adj[i][zeile] = d + min; } } } } } } } } } } } /* DEBUG ONLY */ for (int z = 0; z < N; z++) { for (int s = 0; s < N; s++) { if (adj[s][z] == Integer.MAX_VALUE) { System.out.print("X"); } else { System.out.print(adj[s][z]); } System.out.print(" "); } System.out.print("\n"); } /**/ double[] f = new double[K * 2 + 1]; // -K, 0, +K for (int i = 0; i < K * 2 + 1; i++) { int k = i - K; // start at -K f[i] = 0.0; // initialize to 0 if (k < 0) {// case of -K for (int u = 0; u < N; u++) {// go through all units int xpos = u % xsize; // determine coordinates of current unit int ypos = u / xsize; for (int n = 0; n < 4; n++) {// 4 neighbours int v = -1; if (n == 0 && xpos - 1 >= 0) {// 1st neighbour = left neighbour v = ypos * xsize + xpos - 1; // number of left neighbour unit (if exists) } else if (n == 1 && ypos - 1 >= 0) { // 2nd neighbour = top neighbour v = (ypos - 1) * xsize + xpos; // number of top neighbour unit (if exists) } else if (n == 2 && xpos < xsize - 1) {// right neighbour v = ypos * xsize + xpos + 1; // number of right neighbour (if exists) } else if (n == 3 && ypos < ysize - 1) {// bottom neighbour v = (ypos + 1) * xsize + xpos; // number of bottom neighbour (if exists) } if (v > -1) {// if neighbour exists int d = -1; if (v > u) {// Dreiecksmatrix d = adj[v][u]; } else { d = adj[u][v]; } if (d > k * -1) { f[i] += 1.0; } } } } } else if (k > 0) { for (int z = 0; z < N; z++) { for (int s = z + 1; s < N; s++) { if (adj[s][z] == 1) { int xpos1 = z % xsize; int ypos1 = z / xsize; int xpos2 = s % xsize; int ypos2 = s / xsize; int maxnorm = -1; if (Math.abs(xpos1 - xpos2) > Math.abs(ypos1 - ypos2)) { maxnorm = Math.abs(xpos1 - xpos2); } else { maxnorm = Math.abs(ypos1 - ypos2); } if (maxnorm > k) { f[i] += 1.0; } } } } } f[i] = f[i] / N; } f[K] = f[K - 1] + f[K + 1]; return f; } }