edu.uci.ics.jung.algorithms.importance.AbstractRanker.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.algorithms.importance.AbstractRanker.java

Source

/*
* 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;
    }
}