Java tutorial
/* * Copyright (c) 2003, the JUNG Project and the Regents of the University * of California * All rights reserved. * * This software is open-source under the BSD license; see either * "license.txt" or * http://jung.sourceforge.net/license.txt for a description. */ package edu.uci.ics.jung.algorithms.importance; import java.text.DecimalFormat; import java.text.Format; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections15.Factory; import org.apache.commons.collections15.map.LazyMap; import edu.uci.ics.jung.algorithms.util.IterativeProcess; import edu.uci.ics.jung.graph.Graph; /** * Abstract class for algorithms that rank nodes or edges by some "importance" metric. Provides a common set of * services such as: * <ul> * <li> storing rank scores</li> * <li> getters and setters for rank scores</li> * <li> computing default edge weights</li> * <li> normalizing default or user-provided edge transition weights </li> * <li> normalizing rank scores</li> * <li> automatic cleanup of decorations</li> * <li> creation of Ranking list</li> * <li>print rankings in sorted order by rank</li> * </ul> * <p> * By default, all rank scores are removed from the vertices (or edges) being ranked. * @author Scott White */ public abstract class AbstractRanker<V, E> extends IterativeProcess { private Graph<V, E> mGraph; private List<Ranking<?>> mRankings; private boolean mRemoveRankScoresOnFinalize; private boolean mRankNodes; private boolean mRankEdges; private boolean mNormalizeRankings; protected Map<Object, Map<V, Number>> vertexRankScores = LazyMap.decorate(new HashMap<Object, Map<V, Number>>(), new Factory<Map<V, Number>>() { public Map<V, Number> create() { return new HashMap<V, Number>(); } }); protected Map<Object, Map<E, Number>> edgeRankScores = LazyMap.decorate(new HashMap<Object, Map<E, Number>>(), new Factory<Map<E, Number>>() { public Map<E, Number> create() { return new HashMap<E, Number>(); } }); private Map<E, Number> edgeWeights = new HashMap<E, Number>(); protected void initialize(Graph<V, E> graph, boolean isNodeRanker, boolean isEdgeRanker) { if (!isNodeRanker && !isEdgeRanker) throw new IllegalArgumentException("Must rank edges, vertices, or both"); mGraph = graph; mRemoveRankScoresOnFinalize = true; mNormalizeRankings = true; mRankNodes = isNodeRanker; mRankEdges = isEdgeRanker; } /** * @return all rankScores */ public Map<Object, Map<V, Number>> getVertexRankScores() { return vertexRankScores; } public Map<Object, Map<E, Number>> getEdgeRankScores() { return edgeRankScores; } /** * @return the rankScores */ public Map<V, Number> getVertexRankScores(Object key) { return vertexRankScores.get(key); } public Map<E, Number> getEdgeRankScores(Object key) { return edgeRankScores.get(key); } protected Collection<V> getVertices() { return mGraph.getVertices(); } protected int getVertexCount() { return mGraph.getVertexCount(); } protected Graph<V, E> getGraph() { return mGraph; } @Override public void reset() { } /** * Returns <code>true</code> if this ranker ranks nodes, and * <code>false</code> otherwise. */ public boolean isRankingNodes() { return mRankNodes; } /** * Returns <code>true</code> if this ranker ranks edges, and * <code>false</code> otherwise. */ public boolean isRankingEdges() { return mRankEdges; } /** * Instructs the ranker whether or not it should remove the rank scores from the nodes (or edges) once the ranks * have been computed. * @param removeRankScoresOnFinalize <code>true</code> if the rank scores are to be removed, <code>false</code> otherwise */ public void setRemoveRankScoresOnFinalize(boolean removeRankScoresOnFinalize) { this.mRemoveRankScoresOnFinalize = removeRankScoresOnFinalize; } protected void onFinalize(Object e) { } /** * The user datum key used to store the rank score. * @return the key */ abstract public Object getRankScoreKey(); @Override protected void finalizeIterations() { List<Ranking<?>> sortedRankings = new ArrayList<Ranking<?>>(); int id = 1; if (mRankNodes) { for (V currentVertex : getVertices()) { Ranking<V> ranking = new Ranking<V>(id, getVertexRankScore(currentVertex), currentVertex); sortedRankings.add(ranking); if (mRemoveRankScoresOnFinalize) { this.vertexRankScores.get(getRankScoreKey()).remove(currentVertex); } id++; onFinalize(currentVertex); } } if (mRankEdges) { for (E currentEdge : mGraph.getEdges()) { Ranking<E> ranking = new Ranking<E>(id, getEdgeRankScore(currentEdge), currentEdge); sortedRankings.add(ranking); if (mRemoveRankScoresOnFinalize) { this.edgeRankScores.get(getRankScoreKey()).remove(currentEdge); } id++; onFinalize(currentEdge); } } mRankings = sortedRankings; Collections.sort(mRankings); } /** * Retrieves the list of ranking instances in descending sorted order by rank score * If the algorithm is ranking edges, the instances will be of type <code>EdgeRanking</code>, otherwise * if the algorithm is ranking nodes the instances will be of type <code>NodeRanking</code> * @return the list of rankings */ public List<Ranking<?>> getRankings() { return mRankings; } /** * Return a list of the top k rank scores. * @param topKRankings the value of k to use * @return list of rank scores */ public List<Double> getRankScores(int topKRankings) { List<Double> scores = new ArrayList<Double>(); int count = 1; for (Ranking<?> currentRanking : getRankings()) { if (count > topKRankings) { return scores; } scores.add(currentRanking.rankScore); count++; } return scores; } /** * Given an edge or node, returns the corresponding rank score. This is a default * implementation of getRankScore which assumes the decorations are of type MutableDouble. * This method only returns legal values if <code>setRemoveRankScoresOnFinalize(false)</code> was called * prior to <code>evaluate()</code>. * @return the rank score value */ public double getVertexRankScore(V v) { Number rankScore = vertexRankScores.get(getRankScoreKey()).get(v); if (rankScore != null) { return rankScore.doubleValue(); } else { throw new RuntimeException("setRemoveRankScoresOnFinalize(false) must be called before evaluate()."); } } public double getVertexRankScore(V v, Object key) { return vertexRankScores.get(key).get(v).doubleValue(); } public double getEdgeRankScore(E e) { Number rankScore = edgeRankScores.get(getRankScoreKey()).get(e); if (rankScore != null) { return rankScore.doubleValue(); } else { throw new RuntimeException("setRemoveRankScoresOnFinalize(false) must be called before evaluate()."); } } public double getEdgeRankScore(E e, Object key) { return edgeRankScores.get(key).get(e).doubleValue(); } protected void setVertexRankScore(V v, double rankValue, Object key) { vertexRankScores.get(key).put(v, rankValue); } protected void setEdgeRankScore(E e, double rankValue, Object key) { edgeRankScores.get(key).put(e, rankValue); } protected void setVertexRankScore(V v, double rankValue) { setVertexRankScore(v, rankValue, getRankScoreKey()); } protected void setEdgeRankScore(E e, double rankValue) { setEdgeRankScore(e, rankValue, getRankScoreKey()); } protected void removeVertexRankScore(V v, Object key) { vertexRankScores.get(key).remove(v); } protected void removeEdgeRankScore(E e, Object key) { edgeRankScores.get(key).remove(e); } protected void removeVertexRankScore(V v) { vertexRankScores.get(getRankScoreKey()).remove(v); } protected void removeEdgeRankScore(E e) { edgeRankScores.get(getRankScoreKey()).remove(e); } protected double getEdgeWeight(E e) { return edgeWeights.get(e).doubleValue(); } protected void setEdgeWeight(E e, double weight) { edgeWeights.put(e, weight); } public void setEdgeWeights(Map<E, Number> edgeWeights) { this.edgeWeights = edgeWeights; } /** * @return the edgeWeights */ public Map<E, Number> getEdgeWeights() { return edgeWeights; } protected void assignDefaultEdgeTransitionWeights() { for (V currentVertex : getVertices()) { Collection<E> outgoingEdges = mGraph.getOutEdges(currentVertex); double numOutEdges = outgoingEdges.size(); for (E currentEdge : outgoingEdges) { setEdgeWeight(currentEdge, 1.0 / numOutEdges); } } } protected void normalizeEdgeTransitionWeights() { for (V currentVertex : getVertices()) { Collection<E> outgoingEdges = mGraph.getOutEdges(currentVertex); double totalEdgeWeight = 0; for (E currentEdge : outgoingEdges) { totalEdgeWeight += getEdgeWeight(currentEdge); } for (E currentEdge : outgoingEdges) { setEdgeWeight(currentEdge, getEdgeWeight(currentEdge) / totalEdgeWeight); } } } protected void normalizeRankings() { if (!mNormalizeRankings) { return; } double totalWeight = 0; for (V currentVertex : getVertices()) { totalWeight += getVertexRankScore(currentVertex); } for (V currentVertex : getVertices()) { setVertexRankScore(currentVertex, getVertexRankScore(currentVertex) / totalWeight); } } /** * Print the rankings to standard out in descending order of rank score * @param verbose if <code>true</code>, include information about the actual rank order as well as * the original position of the vertex before it was ranked * @param printScore if <code>true</code>, include the actual value of the rank score */ public void printRankings(boolean verbose, boolean printScore) { double total = 0; Format formatter = new DecimalFormat("#0.#######"); int rank = 1; for (Ranking<?> currentRanking : getRankings()) { double rankScore = currentRanking.rankScore; if (verbose) { System.out.print("Rank " + rank + ": "); if (printScore) { System.out.print(formatter.format(rankScore)); } System.out.print("\tVertex Id: " + currentRanking.originalPos); System.out.print(" (" + currentRanking.getRanked() + ")"); System.out.println(); } else { System.out.print(rank + "\t"); if (printScore) { System.out.print(formatter.format(rankScore)); } System.out.println("\t" + currentRanking.originalPos); } total += rankScore; rank++; } if (verbose) { System.out.println("Total: " + formatter.format(total)); } } /** * Allows the user to specify whether or not s/he wants the rankings to be normalized. * In some cases, this will have no effect since the algorithm doesn't allow normalization * as an option * @param normalizeRankings */ public void setNormalizeRankings(boolean normalizeRankings) { mNormalizeRankings = normalizeRankings; } }