/* * Copyright (C) 2010-2014 Mathias Unberath CONRAD is developed as an Open * Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.conrad.io; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.StringTokenizer; import edu.stanford.rsl.conrad.geometry.shapes.activeshapemodels.KPCA; import edu.stanford.rsl.conrad.geometry.shapes.activeshapemodels.kernels.GaussianKernel; import edu.stanford.rsl.conrad.geometry.shapes.activeshapemodels.kernels.PolynomialKernel; import edu.stanford.rsl.conrad.geometry.shapes.mesh.DataMatrix; import edu.stanford.rsl.conrad.numerics.SimpleMatrix; import edu.stanford.rsl.conrad.numerics.SimpleVector; /** * Class to read and write Eigenvectors, Eigenvalues and the training-sets as * used in kernel principal component analysis. * * @author Mathias Unberath * */ public class KpcaIO { /** * Dimension of vertices in a mesh object. Default is 1; */ private int pointDimension = 1; /** * The filename for input or output operation. */ String filename; /** * Array containing the eigenvalues of the covariance matrix after singular * value decomposition. */ private double[] eigenValues; /** * Matrix containing the Eigenvectors of the covariance matrix after * singular value decomposition. */ private SimpleMatrix eigenVectors; /** * Training-sets. */ private SimpleMatrix trainingSets; /** * Feature Matrix K. */ private SimpleMatrix featureMatrix; /** * Consensus object needed to project new shapes. */ private SimpleVector consensus; /** * The name of the kernel. */ private String kernel; /** * The variation threshold used to reduce dimensionality. */ private double variation; // ========================================================================================== // METHODS // ========================================================================================== /** * Constructor for KPCA writing operation. * @param filename * @param kpca */ public KpcaIO(String filename, KPCA kpca) { this.filename = filename; this.pointDimension = kpca.dimension; this.eigenValues = kpca.eigenValues; this.eigenVectors = kpca.eigenVectors; // the eigenvectors are commonly referred to as alpha this.trainingSets = kpca.data; this.featureMatrix = kpca.getFeatureMatrix(); this.consensus = toSimpleVector(kpca.data.consensus); this.kernel = kpca.kernel.getName(); this.variation = kpca.variationThreshold; } /** * Constructor for reading operation. * @param filename The filename containing the Kpca Object as produced by this class */ public KpcaIO(String filename){ this.filename = filename; } /** * Writes the previously set KPCA object to the specified file. */ public void writeFile(){ assert( filename != null) : new Exception("Filename not set."); assert( consensus != null && eigenVectors != null && eigenValues != null && trainingSets != null && featureMatrix != null && kernel != null) : new Exception("Data not set."); System.out.println("Writing to file: " + filename); try{ System.out.println("Writing Eigen-Values and Eigen-Vectors to file: " + filename); PrintWriter writer = new PrintWriter(filename,"UTF-8"); writer.println("Number of datasets: " + Integer.valueOf(trainingSets.getCols())); writer.println("Number of points: " + Integer.valueOf(trainingSets.getRows()/pointDimension)); writer.println("Point dimension: " + Integer.valueOf(pointDimension)); writer.println("Number of P.C.s: " + Integer.valueOf(eigenValues.length)); writer.println("Variation threshold: " + Double.valueOf(variation)); writer.println("Kernel: " + kernel); writer.println(""); writer.println("EIGENVALUES of K_ij"); String eval = ""; for(int i = 0; i < eigenValues.length; i++){ eval += (Double.valueOf(eigenValues[i]) + " "); } writer.println(eval); writer.println("EIGENVECTORS of K_ij"); for(int i = 0; i < trainingSets.getCols(); i++){ writer.println(rowAsString(eigenVectors, i)); } writer.println("FEATUREMATRIX K_ij"); for(int i = 0; i < trainingSets.getCols(); i++){ writer.println(rowAsString(featureMatrix, i)); } writer.println("TRAININGSETS | CONSENSUS"); for(int i = 0; i < trainingSets.getRows(); i++){ writer.println(rowAsString(trainingSets, i) + Double.valueOf(consensus.getElement(i))); } writer.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } /** * Constructs a KPCA object from the data given in the file referred to by filename. * @return KPCA object */ public KPCA readFile(){ assert(filename != null) : new Exception("Filename not set."); KPCA kpca= new KPCA(); FileReader fr; try { fr = new FileReader(filename); BufferedReader br = new BufferedReader(fr); String line = br.readLine(); StringTokenizer tok = new StringTokenizer(line); tok.nextToken(); // skip "Number of Datasets" tok.nextToken(); tok.nextToken(); String t = tok.nextToken(); kpca.numSamples = Integer.parseInt(t); line = br.readLine(); tok = new StringTokenizer(line); tok.nextToken(); // skip "Number of points" tok.nextToken(); tok.nextToken(); t = tok.nextToken(); kpca.numVertices = Integer.parseInt(t); line = br.readLine(); tok = new StringTokenizer(line); tok.nextToken(); // skip "Point dimension" tok.nextToken(); t = tok.nextToken(); kpca.dimension = Integer.parseInt(t); kpca.numPoints = kpca.numVertices * kpca.dimension; line = br.readLine(); tok = new StringTokenizer(line); tok.nextToken(); // skip "Number of Pcs" tok.nextToken(); tok.nextToken(); t = tok.nextToken(); int numPC = Integer.parseInt(t); line = br.readLine(); tok = new StringTokenizer(line); tok.nextToken(); // skip "Variation threshold" tok.nextToken(); t = tok.nextToken(); kpca.variationThreshold = Double.parseDouble(t); line = br.readLine(); tok = new StringTokenizer(line); tok.nextToken(); // skip "Kernel" t = tok.nextToken(); String kernelName = t; t = tok.nextToken(); double val = Double.parseDouble(t); if(kernelName.equals("Gaussian")){ kpca.kernel = new GaussianKernel(val); }else if(kernelName.equals("Polynomial")){ double alpha = Double.valueOf(tok.nextToken()); double offs = Double.valueOf(tok.nextToken()); kpca.kernel = new PolynomialKernel((int) val, alpha, offs); }else{ System.out.println("Kernel method unknown. Using default: parabolic kernel."); kpca.kernel = new PolynomialKernel(); } // read the EIGENVALUES br.readLine(); br.readLine(); // skip empty line, then skip "EIGENVALUES ..." line = br.readLine(); tok = new StringTokenizer(line); double[] ev = new double[numPC]; for(int i = 0; i < numPC; i++){ t = tok.nextToken(); ev[i] = Double.parseDouble(t); } kpca.eigenValues = ev; // read the EIGENVECTORS br.readLine(); // skip "EIGENVECTORS ..." SimpleMatrix evec = new SimpleMatrix(kpca.numSamples, numPC); for(int i = 0; i < kpca.numSamples; i++){ line = br.readLine(); tok = new StringTokenizer(line); for(int j = 0; j < numPC; j++){ t = tok.nextToken(); evec.setElementValue(i, j, Double.parseDouble(t)); } } kpca.eigenVectors = evec; // read the Feature Matrix br.readLine(); // skip "FEATUREMATRIX ..." SimpleMatrix feat = new SimpleMatrix(kpca.numSamples, kpca.numSamples); for(int i = 0; i < kpca.numSamples; i++){ line = br.readLine(); tok = new StringTokenizer(line); for(int j = 0; j < kpca.numSamples; j++){ t = tok.nextToken(); feat.setElementValue(i, j, Double.parseDouble(t)); } } kpca.setFeatureMatrix(feat); // read the trainingssets and consensus br.readLine(); // skip "FEATUREMATRIX ..." DataMatrix m = new DataMatrix(); m.init(kpca.numPoints, kpca.numSamples); m.dimension = kpca.dimension; SimpleMatrix consensus = new SimpleMatrix(kpca.numVertices, kpca.dimension); for(int i = 0; i < kpca.numPoints; i++){ int idxx = (int)Math.floor((float)i/kpca.dimension); int idxy = i - idxx * kpca.dimension; SimpleVector vec = new SimpleVector(kpca.numSamples); line = br.readLine(); tok = new StringTokenizer(line); for(int j = 0; j < kpca.numSamples; j++){ t = tok.nextToken(); if(j == kpca.numSamples-1){ consensus.setElementValue(idxx, idxy, Double.parseDouble(t)); }else{ vec.setElementValue(j, Double.parseDouble(t)); } } } m.consensus = consensus; kpca.data = m; br.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return kpca; } /** * Condenses the i_th row of a simple matrix into a string. * @param m * @param row * @return i_th row as string */ private String rowAsString(SimpleMatrix m, int row){ String r = ""; for(int i = 0; i < m.getCols(); i++){ r += (Double.valueOf(m.getElement(row, i)) + " "); } return r; } /** * Transforms a SimpleMatrix into a SimpleVector by appending each consecutive row to the former. * @param m The SimpleMatrix. * @return The SimpleMatrix as SimpleVector. */ private SimpleVector toSimpleVector(SimpleMatrix m){ SimpleVector v = new SimpleVector(m.getRows() * m.getCols()); for(int i = 0; i < m.getRows(); i++){ for(int j = 0; j < m.getCols(); j++){ v.setElementValue(i * m.getCols() + j, m.getElement(i, j)); } } return v; } }