/*
* 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;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;
import at.tuwien.ifs.somtoolbox.SOMToolboxException;
import at.tuwien.ifs.somtoolbox.data.InputDatum;
import at.tuwien.ifs.somtoolbox.input.SOMLibFileFormatException;
import at.tuwien.ifs.somtoolbox.input.SOMLibMapDescription;
import at.tuwien.ifs.somtoolbox.layers.metrics.DistanceMetric;
import at.tuwien.ifs.somtoolbox.layers.metrics.MetricException;
import at.tuwien.ifs.somtoolbox.util.FileUtils;
import at.tuwien.ifs.somtoolbox.util.StringUtils;
/**
* @author Rudolf Mayer
* @version $Id: AdaptiveCoordinatesVirtualLayer.java 3869 2010-10-21 15:56:09Z mayer $
*/
public class AdaptiveCoordinatesVirtualLayer {
public static final String FILE_EXTENSION = "adaptiveCoord";
private HashMap<Double, AdaptiveCoordinatesVirtualUnit[][]> virtualUnits = new HashMap<Double, AdaptiveCoordinatesVirtualUnit[][]>();
private HashMap<Double, Integer> startedVirtualAdaptionIn = new HashMap<Double, Integer>();
private double[] thresholds;
private int xSize;
private int ySize;
public AdaptiveCoordinatesVirtualLayer(int ySize, int xSize, double... acThreshold) {
this.thresholds = acThreshold;
this.xSize = xSize;
this.ySize = ySize;
for (double element : acThreshold) {
AdaptiveCoordinatesVirtualUnit[][] virtualUnitsTemp = new AdaptiveCoordinatesVirtualUnit[xSize][ySize];
for (int j = 0; j < ySize; j++) {
for (int i = 0; i < xSize; i++) {
virtualUnitsTemp[i][j] = new AdaptiveCoordinatesVirtualUnit(i, j);
}
}
virtualUnits.put(element, virtualUnitsTemp);
}
}
public AdaptiveCoordinatesVirtualLayer(String fileName) throws IOException, SOMToolboxException {
String fileType = "Adaptive Coordinates file";
BufferedReader br = FileUtils.openFile(fileType, fileName);
Map<String, String> headers = FileUtils.readSOMLibFileHeaders(br, fileType);
String line = headers.get("FIRST_CONTENT_LINE");
int index = Integer.parseInt(headers.get("LINE_NUMBER"));// line counter
if (index < 2) {
throw new SOMToolboxException(fileType + ": no header line starting with $ found");
}
xSize = Integer.parseInt(headers.get("$XDIM"));
ySize = Integer.parseInt(headers.get("$XDIM"));
int nrThresholds = Integer.parseInt(headers.get("$ZDIM"));
thresholds = StringUtils.parseDoubles(headers.get(SOMLibMapDescription.ADAPTIVE_COORDINATES_THRESHOLD));
if (nrThresholds != thresholds.length) {
throw new SOMLibFileFormatException("$ZDIM of " + nrThresholds + " and actually found " + thresholds.length
+ " thresholds do not match! Error in line " + index);
}
for (double threshold : thresholds) {
virtualUnits.put(threshold, new AdaptiveCoordinatesVirtualUnit[xSize][ySize]);
}
while (line != null) {
String[] parts = line.split(" ");
if (parts.length < 4) { // need at least 4 values (x & y, and adaptive coordinates x & y)
throw new SOMLibFileFormatException("Number of elements per line must be at least 4! Error in line "
+ index);
}
if (parts.length % 2 != 0) { // uneven numbers must not happen
throw new SOMLibFileFormatException("Number of elements per line must be multiple of 2! Error in line "
+ index);
}
int xPos = Integer.parseInt(parts[0]);
int yPos = Integer.parseInt(parts[1]);
for (int i = 2; i < parts.length; i += 2) {
double acXPos = Double.parseDouble(parts[i]);
double acYPos = Double.parseDouble(parts[i + 1]);
double threshold = thresholds[(i - 2) / 2];
virtualUnits.get(threshold)[xPos][yPos] = new AdaptiveCoordinatesVirtualUnit(acXPos, acYPos);
}
line = br.readLine();
}
// check whether we have found all units in the file
for (double threshold : thresholds) {
for (int j = 0; j < ySize; j++) {
for (int i = 0; i < xSize; i++) {
if (virtualUnits.get(threshold)[i][j] == null) {
throw new SOMLibFileFormatException("The " + fileType
+ "didn't contain any information about unit " + i + "/" + j + " for threshold "
+ threshold + ".");
}
}
}
}
}
/**
* Updates the virtual space position of all map units with respect to the input datum and the according winner
* unit. See Adaptive Coordinates approach.
*
* @param winner the winner unit
* @param input the input datum
* @param curIteration the current iteration
*/
public void updateUnitsVirtualSpacePos(Unit[][][] units, DistanceMetric metric, Unit winner, InputDatum input,
int curIteration) {
for (double threshold : thresholds) {
double[] inputVector = input.getVector().toArray();
if (curIteration > threshold * xSize * ySize) {
if (startedVirtualAdaptionIn.get(threshold) == null) {
Logger.getLogger("at.tuwien.ifs.somtoolbox").info(
"Iteration " + curIteration + ": started training virtual layer for threshold " + threshold);
startedVirtualAdaptionIn.put(threshold, curIteration);
}
AdaptiveCoordinatesVirtualUnit virtualWinner = virtualUnits.get(threshold)[winner.getXPos()][winner.getYPos()];
// No adaption during the first few training cycles
int k = 0;
for (int j = 0; j < ySize; j++) {
for (int i = 0; i < xSize; i++) {
try {
double unitDistanceToInputAfterAdaption = metric.distance(units[i][j][k].getWeightVector(),
inputVector);
virtualUnits.get(threshold)[i][j].updateAdaptiveCoordinates(
unitDistanceToInputAfterAdaption, virtualWinner.getAXPos(),
virtualWinner.getAYPos());
} catch (MetricException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
public AdaptiveCoordinatesVirtualUnit getVirtualUnit(double threshold, int x, int y) {
return virtualUnits.get(threshold)[x][y];
}
public int getXSize() {
return xSize;
}
public int getYSize() {
return ySize;
}
public void writeToFile(String fDir, String fName) throws IOException {
boolean gzipped = true;
BufferedWriter bw = null;
String finalName = FileUtils.getPathPrefix(fDir) + fName + FileUtils.getSuffix(FILE_EXTENSION, gzipped);
if (gzipped == true) {
bw = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(finalName))));
} else {
bw = new BufferedWriter(new FileWriter(finalName));
}
Logger.getLogger("at.tuwien.ifs.somtoolbox").info(
"Saving SOMLib adaptive coordinates file " + finalName + " (" + new File(finalName).getAbsolutePath()
+ ")");
bw.write("$TYPE ADAPTIVE_COORDINATES");
bw.newLine();
bw.write("$FILE_FORMAT_VERSION 1.0");
bw.newLine();
bw.write("$XDIM " + getXSize());
bw.newLine();
bw.write("$YDIM " + getYSize());
bw.newLine();
bw.write("$ZDIM " + thresholds.length); // the number of thresholds
bw.newLine();
bw.write(SOMLibMapDescription.ADAPTIVE_COORDINATES_THRESHOLD + " " + StringUtils.toString(thresholds, "", ""));
bw.newLine();
for (int j = 0; j < getYSize(); j++) {
for (int i = 0; i < getXSize(); i++) {
bw.write(i + " " + j);
for (double threshold : thresholds) {
bw.write(" " + virtualUnits.get(threshold)[i][j].getAXPos() + " "
+ virtualUnits.get(threshold)[i][j].getAYPos());
}
bw.write("\n");
}
}
bw.flush();
bw.close();
}
protected void printAdaptiveCoordinates() {
for (double threshold : thresholds) {
System.out.println("\n=================== Threshold " + threshold);
for (int j = 0; j < getYSize(); j++) {
for (int i = 0; i < getXSize(); i++) {
AdaptiveCoordinatesVirtualUnit acu = virtualUnits.get(threshold)[i][j];
System.out.print(StringUtils.format(acu.getAXPos(), 5, true) + "/"
+ StringUtils.format(acu.getAYPos(), 5, true) + "\t");
}
System.out.println();
}
}
}
public void setDistanceToWinner(int x, int y, double distanceToWinners) {
for (double threshold : thresholds) {
getVirtualUnit(threshold, x, y).setDistanceToWinner(distanceToWinners);
}
}
/** @return Returns the adaptive coordinates thresholds used for this set of virtual layers. */
public double[] getThresholds() {
return thresholds;
}
}