package edu.nd.nina.alg; import java.util.Collections; import java.util.Hashtable; import java.util.Vector; import cern.colt.matrix.DoubleMatrix2D; import cern.colt.matrix.impl.DenseDoubleMatrix2D; import edu.nd.nina.Graph; import edu.nd.nina.Graphs; import edu.nd.nina.structs.Pair; /** * Static convenience class for SVD Computation * * @author Tim Weninger * * @param <V> * Node type * @param <E> * Edge type */ public class SingularValueDecomposition<V, E> { /** * Computes largest singular values of the adjacency matrix representing a * Graph. * * @param graph * Graph snapshot * @param singularValues * Number of singular values to get * @return Vector<Singular Values> */ public static <V extends Comparable<V>, E> Vector<Float> getSingularValues( Graph<V, E> graph, final int singularValues) { final int Nodes = graph.vertexSet().size(); Vector<Float> singularValuesV = new Vector<Float>(); assert (singularValues > 0); Hashtable<Object, Integer> nodeToIdH = new Hashtable<Object, Integer>(); // perform full SVD DoubleMatrix2D adjacencyMatrix = new DenseDoubleMatrix2D(Nodes, Nodes); // create adjacency matrix int i = 0; for (V v : graph.vertexSet()) { nodeToIdH.put(v, i); i++; } for (V v : graph.vertexSet()) { final int vId = nodeToIdH.get(v); for (V t : Graphs.neighborListOf(graph, v)) { int tId = nodeToIdH.get(t); adjacencyMatrix.set(vId, tId, 1f); } } try { // can fail to converge but results seem to be good cern.colt.matrix.linalg.SingularValueDecomposition svd = new cern.colt.matrix.linalg.SingularValueDecomposition( adjacencyMatrix); for (Double d : svd.getSingularValues()) { singularValuesV.add((float) (double) d); } } catch (Exception e) { e.printStackTrace(); System.err.printf("\n***No SVD convergence: G(%d, %d)\n", Nodes, graph.edgeSet().size()); } return singularValuesV; } /** * Computes the leading left and right singular vector of the adjacency * matrix representing a directed Graph. * * @param graph * Graph snapshot * @param leftV * Left singular vector * @param rightV * Right singular vector * @return Vector<Singular Values> */ public static <V extends Comparable<V>, E> Vector<Float> getSingularValuesVector( Graph<V, E> graph, Vector<Float> leftV, Vector<Float> rightV) { final int Nodes = graph.vertexSet().size(); Vector<Float> singularValuesV = new Vector<Float>(); Hashtable<Object, Integer> nodeToIdH = new Hashtable<Object, Integer>(); // perform full SVD DoubleMatrix2D adjacencyMatrix = new DenseDoubleMatrix2D(Nodes, Nodes); // create adjecency matrix int i = 0; for (Object v : graph.vertexSet()) { nodeToIdH.put(v, i); i++; } for (V v : graph.vertexSet()) { final int vId = nodeToIdH.get(v); for (V t : Graphs.neighborListOf(graph, v)) { int tId = nodeToIdH.get(t); adjacencyMatrix.set(vId, tId, 1f); } } try { // can fail to converge but results seem to be good cern.colt.matrix.linalg.SingularValueDecomposition svd = new cern.colt.matrix.linalg.SingularValueDecomposition( adjacencyMatrix); for (Double d : svd.getSingularValues()) { singularValuesV.add((float) (double) d); } Vector<Pair<Float, Integer>> singularValuesIdV = new Vector<Pair<Float, Integer>>(); for (int z = 0; z < singularValuesV.size(); z++) { singularValuesIdV.add(new Pair<Float, Integer>(singularValuesV .get(z), z)); } Collections.sort(singularValuesIdV); Collections.sort(singularValuesV); for (int v = 0; v < singularValuesIdV.size(); v++) { for (int w = 0; w < adjacencyMatrix.rows(); w++) { leftV.add((float) svd.getU().get(w, singularValuesIdV.get(v).p2)); } for (int w = 0; w < adjacencyMatrix.rows(); w++) { rightV.add((float) svd.getV().get(w, singularValuesIdV.get(v).p2)); } } } catch (Exception e) { e.printStackTrace(); System.err.printf("\n***No SVD convergence: G(%d, %d)\n", Nodes, graph.edgeSet().size()); } return singularValuesV; } }