edu.uci.ics.jung.utils.GraphUtils.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.utils.GraphUtils.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.
 */
/*
 * Created on Jun 25, 2003
 */
package edu.uci.ics.jung.utils;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;

import cern.colt.list.DoubleArrayList;
import edu.uci.ics.jung.algorithms.transformation.DirectionTransformer;
import edu.uci.ics.jung.graph.ArchetypeEdge;
import edu.uci.ics.jung.graph.ArchetypeGraph;
import edu.uci.ics.jung.graph.ArchetypeVertex;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Hyperedge;
import edu.uci.ics.jung.graph.Hypergraph;
import edu.uci.ics.jung.graph.Hypervertex;
import edu.uci.ics.jung.graph.UndirectedGraph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.decorators.Indexer;
import edu.uci.ics.jung.graph.decorators.NumberVertexValue;
import edu.uci.ics.jung.graph.decorators.StringLabeller;
import edu.uci.ics.jung.graph.decorators.StringLabeller.UniqueLabelException;
import edu.uci.ics.jung.graph.filters.UnassembledGraph;
import edu.uci.ics.jung.graph.filters.impl.DropSoloNodesFilter;
import edu.uci.ics.jung.graph.impl.AbstractSparseEdge;
import edu.uci.ics.jung.graph.impl.DirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.DirectedSparseVertex;
import edu.uci.ics.jung.graph.impl.SparseVertex;
import edu.uci.ics.jung.graph.impl.UndirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.UndirectedSparseVertex;

/**
 * 
 * A series of helpful utility methods. All methods in GraphUtils can be
 * accomplished with public members of other code; these are simply
 * combinations that we found useful.
 * 
 * @author Danyel Fisher, Scott White, Joshua O'Madadhain
 */
public class GraphUtils {

    /**
     * Adds an appropriate edge between two vertices. Specifically, this method
     * confirms that both vertices are from the same graph, and then checks
     * whether the Graph is directed or not. If
     * so, it creates a new
     * {@link  edu.uci.ics.jung.graph.impl.DirectedSparseEdge DirectedSparseEdge},
     * otherwise a new
     * {@link  edu.uci.ics.jung.graph.impl.UndirectedSparseEdge UndirectedSparseEdge}.
     * This is a convenience method; one might instead just call <code> g.addEdge( new XXSparseEdge(v1, v2))) </code>.
     * <p>
     * The input vertices must be of type {@link edu.uci.ics.jung.graph.Vertex},
     * or the method will throw a <code>ClassCastException</code>.
     * 
     * @throws ClassCastException
     *             if the input aren't Vertices
     * @throws IllegalArgumentException
     *             if the vertices don't belong to the same graph
     * 
     * @return the edge that was added
     * 
     * @see edu.uci.ics.jung.graph.Graph#addEdge
     * @see edu.uci.ics.jung.graph.impl.AbstractSparseGraph#addEdge
     */
    public static Edge addEdge(Graph g, Vertex v1, Vertex v2) {
        if (v1.getGraph() != g || v2.getGraph() != g)
            throw new IllegalArgumentException("Vertices not in this graph!");
        if (PredicateUtils.enforcesEdgeConstraint(g, Graph.DIRECTED_EDGE)) {
            return (AbstractSparseEdge) g.addEdge(new DirectedSparseEdge(v1, v2));
        } else if (PredicateUtils.enforcesEdgeConstraint(g, Graph.UNDIRECTED_EDGE)) {
            return (AbstractSparseEdge) g.addEdge(new UndirectedSparseEdge(v1, v2));
        } else
            throw new IllegalArgumentException(
                    "Behavior not specified " + "for mixed (directed/undirected) graphs");
    }

    /**
     * Adds <code>count</code> vertices into a graph. This is a convenience
     * method; one might instead just call <code> g.addVertex( new SparseVertex())) </code>
     * <code>count</code>
     * times.
     * <p>
     * The input graph must be one that can accept a series of
     * {@link edu.uci.ics.jung.graph.impl.SparseVertex directed vertices}.
     * 
     * @param g
     *            A graph to add the vertices to
     * @param count
     *            how many vertices to add
     * 
     * @see edu.uci.ics.jung.graph.impl.AbstractSparseGraph#addVertex
     */
    public static void addVertices(Graph g, int count) {
        for (int i = 0; i < count; i++)
            g.addVertex(new SparseVertex());
    }

    /**
     * Adds <code>count</code> directed vertices into a graph. This is a
     * convenience method; one might instead just call <code> g.addVertex( new DirectedSparseVertex())) </code>
     * <code>count</code>
     * times.
     * <p>
     * The input graph must be one that can accept a series of
     * {@link edu.uci.ics.jung.graph.impl.DirectedSparseVertex directed vertices}.
     * 
     * @param g
     *            A graph to add the vertices to
     * @param count
     *            how many vertices to add
     * 
     * @see edu.uci.ics.jung.graph.impl.AbstractSparseGraph#addVertex
     * @deprecated As of version 1.2, replaced by {@link #addVertices}.
     */
    public static void addDirectedVertices(Graph g, int count) {
        for (int i = 0; i < count; i++) {
            g.addVertex(new DirectedSparseVertex());
        }
    }

    /**
     * Adds <code>count</code> undirected vertices into a graph. This is a
     * convenience method; one might instead just call <code> g.addVertex( new UndirectedSparseVertex())) </code>
     * <code>count</code>
     * times.
     * <p>
     * The input graph must be one that can accept a series of
     * {@link edu.uci.ics.jung.graph.impl.UndirectedSparseVertex undirected vertices}.
     * 
     * @param g
     *            A graph to add the vertices to
     * @param count
     *            how many vertices to add
     * 
     * @see edu.uci.ics.jung.graph.impl.AbstractSparseGraph#addVertex
     * @deprecated As of version 1.2, replaced by {@link #addVertices}.
     */
    public static void addUndirectedVertices(Graph g, int count) {
        for (int i = 0; i < count; i++) {
            g.addVertex(new UndirectedSparseVertex());
        }
    }

    /**
     * Translates every vertex from the input <code>set</code> into the graph
     * given. For each vertex, then, it gets the equivalent vertex in <code>g</code>,
     * and returns the collated set.
     * 
     * @param s
     *            The set of input vertices, not from g
     * @param g
     *            The graph which has the corresponding vertices
     * 
     * @return a resulting set
     * 
     * @see edu.uci.ics.jung.graph.ArchetypeVertex#getEqualVertex
      * @deprecated As of version 1.4, replaced by {@link GraphUtils#getEqualVertices(Set, ArchetypeGraph)}
     */
    public static Set translateAll(Set s, Graph g) {
        return getEqualVertices(s, g);
    }

    /**
     * Returns the set of vertices in <code>g</code> which are equal
     * to the vertices in <code>g</code>.
     * @since 1.4
     */
    public static Set getEqualVertices(Set s, ArchetypeGraph g) {
        Set rv = new HashSet();
        for (Iterator iter = s.iterator(); iter.hasNext();) {
            ArchetypeVertex v = (ArchetypeVertex) iter.next();
            ArchetypeVertex v_g = v.getEqualVertex(g);
            if (v_g != null)
                rv.add(v_g);
        }
        return rv;
    }

    /**
     * Translates every edge from the input <code>set</code> into the graph
     * given. For each edge, then, it gets the equivalent edge in <code>g</code>,
     * and returns the collated set.
     * 
     * @param s
     *            The set of input edges, not from g
     * @param g
     *            The graph which has the corresponding edges
     * 
     * @return a resulting set
     * 
     * @see edu.uci.ics.jung.graph.ArchetypeEdge#getEqualEdge
      * @deprecated As of version 1.4, replaced by {@link GraphUtils#getEqualEdges(Set, ArchetypeGraph)}
     */
    public static Set translateAllEdges(Set s, Graph g) {
        return getEqualEdges(s, g);
    }

    /**
     * Returns the set of edges in <code>g</code> which are equal
     * to the edges in <code>g</code>.
     * @since 1.4
     */
    public static Set getEqualEdges(Set s, ArchetypeGraph g) {
        Set rv = new HashSet();
        for (Iterator iter = s.iterator(); iter.hasNext();) {
            ArchetypeEdge e = (ArchetypeEdge) iter.next();
            ArchetypeEdge e_g = e.getEqualEdge(g);
            if (e_g != null)
                rv.add(e_g);
        }
        return rv;
    }

    /**
     * Given a set of vertices, creates a new <tt>Graph</tt> that contains
     * all of those vertices, and all the edges that connect them. Uses the
     * <tt>{@link edu.uci.ics.jung.graph.filters.UnassembledGraph UnassembledGraph}</tt>
     * mechanism to create the graph.
     * 
     * @param s
     *            A set of <tt>Vertex</tt> s that want to be a part of a new
     *            Graph
     * @return A graph, created with <tt>{@link edu.uci.ics.jung.graph.Graph#newInstance Graph.newInstance}</tt>,
     *         containing vertices equivalent to (and that are copies of!) all
     *         the vertices in the input set. Note that if the input is an
     *         empty set, <tt>null</tt> is returned.
     */
    public static Graph vertexSetToGraph(Set s) {
        if (s.isEmpty())
            return null;
        Vertex v = (Vertex) s.iterator().next();
        Graph g = (Graph) v.getGraph();
        return new UnassembledGraph("vertexSetToGraph", s, g.getEdges(), g).assemble();
    }

    /**
     * Given a set of edges, creates a new <tt>Graph</tt> that contains all
     * of those edges, and at least all the vertices that are attached to them.
     * Uses <tt>{@link edu.uci.ics.jung.graph.filters.UnassembledGraph UnassembledGraph}</tt>
     * mechanism to create the graph. The parameter decides what to do with
     * disconnected vertices: <tt>true</tt> says that they should be
     * retained, <tt>false</tt> says that they should be discarded (with a
     * {@link edu.uci.ics.jung.graph.filters.impl.DropSoloNodesFilter DropSoloNodesFilter}).
     * 
     * @param edges
     *            A set of <tt>Edge</tt> s that want to be a part of a new
     *            <tt>Graph</tt>
     * @param retain
     *            Is true if all isolated vertices should be retained; is false if they
     *            should be discarded.
     * @return A graph, created with <tt>{@link edu.uci.ics.jung.graph.Graph#newInstance Graph.newInstance}</tt>,
     *         containing edges equivalent to (and that are copies of!) all the
     *         edges in the input set. Note that if the input is an empty set,
     *         <tt>null</tt> is returned.
     */
    public static Graph edgeSetToGraph(Set edges, boolean retain) {
        if (edges.isEmpty())
            return null;
        Edge e = (Edge) edges.iterator().next();
        Graph g = (Graph) e.getGraph();
        Graph retval = new UnassembledGraph("edgeSetToGraph", g.getVertices(), edges, g).assemble();
        if (retain)
            return retval;
        else {
            return DropSoloNodesFilter.getInstance().filter(retval).assemble();
        }
    }

    /**
     * Returns a graph which consists of the union of the two input graphs.
     * Assumes that both graphs are of a type that can accept the vertices
     * and edges found in both graphs.
     * The resultant graph contains all constraints that are common to both graphs.
     */
    public static ArchetypeGraph union(ArchetypeGraph g1, ArchetypeGraph g2) {
        ArchetypeGraph g = g1.newInstance();
        //        g.getEdgeConstraints().clear();
        g.getEdgeConstraints()
                .addAll(CollectionUtils.intersection(g1.getEdgeConstraints(), g2.getEdgeConstraints()));

        Collection vertices = CollectionUtils.union(g1.getVertices(), g2.getVertices());
        Collection edges = CollectionUtils.union(g1.getEdges(), g2.getEdges());

        for (Iterator v_iter = vertices.iterator(); v_iter.hasNext();) {
            ArchetypeVertex v = (ArchetypeVertex) v_iter.next();
            v.copy(g);
        }

        for (Iterator e_iter = edges.iterator(); e_iter.hasNext();) {
            ArchetypeEdge e = (ArchetypeEdge) e_iter.next();
            e.copy(g);
        }
        return g;
    }

    /**
     * Transforms an (possibly undirected) graph into a directed graph. All user data on
     * the graph,edges & vertices are copied to their corresponding
     * counterparts. Returns a new graph with a directed edge from a to b iff a
     * was a predecessor of b in the original. For an undirected edge, this will create
     * two new edges.
     * 
     * @param uGraph
     *            the undirected graph to transform
     * @return the resultant directed graph
      * @deprecated As of version 1.4, replaced by 
      * {@link edu.uci.ics.jung.algorithms.transformation.DirectionTransformer#toDirected(Graph)}
     */
    public static DirectedGraph transform(Graph uGraph) {
        return DirectionTransformer.toDirected(uGraph);
    }

    /**
     * Transforms a directed graph into a undirected graph. All user data on
     * the graph,edges & vertices are copied to their corresponding
     * counterparts.
     * 
     * @param dGraph
     *            the directed graph to transform
     * @return the resultant undirected graph
      * @deprecated As of version 1.4, replaced by 
      * {@link edu.uci.ics.jung.algorithms.transformation.DirectionTransformer#toUndirected(Graph)}
     */
    public static UndirectedGraph transform(DirectedGraph dGraph) {
        return DirectionTransformer.toUndirected(dGraph);
    }

    /**
     * Copies the labels of vertices from one StringLabeller to another. Only
     * the labels of vertices that are equivalent are copied.
     * 
     * @param source
     *            the source StringLabeller
     * @param target
     *            the target StringLabeller
     */
    public static void copyLabels(StringLabeller source, StringLabeller target) throws UniqueLabelException {
        Graph g1 = source.getGraph();
        Graph g2 = target.getGraph();
        Set s1 = g1.getVertices();
        Set s2 = g2.getVertices();

        for (Iterator iter = s1.iterator(); iter.hasNext();) {
            Vertex v = (Vertex) iter.next();
            if (s2.contains(v)) {
                target.setLabel((Vertex) v.getEqualVertex(g2), source.getLabel(v));
            }
        }
    }

    /**
     * Returns true if <code>g1</code> and <code>g2</code> have equivalent
     * vertex and edge sets (that is, if each vertex and edge in <code>g1</code>
     * has an equivalent in <code>g2</code>, and vice versa), and false
     * otherwise.
     */
    public static boolean areEquivalent(ArchetypeGraph g1, ArchetypeGraph g2) {
        return ((g1 == g2) || (g1.getVertices().equals(g2.getVertices()) && g1.getEdges().equals(g2.getEdges())));
    }

    /**
     * For every vertex in s, prints sl.get(s). S must be made up of only
     * vertices.
     * 
     * @param s
     * @param sl
     */
    public static String printVertices(Collection s, StringLabeller sl) {
        StringBuffer sb = new StringBuffer();
        boolean first = true;
        sb.append("[");
        for (Iterator iter = s.iterator(); iter.hasNext();) {
            Vertex v = (Vertex) iter.next();
            if (!first)
                sb.append(", ");
            else
                first = false;
            sb.append(sl.getLabel(v));

        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * Copies, for each vertex <code>v</code> in <code>g</code>, 
     * <code>source</code>'s value to <code>dest</code>.
     * @param g         the graph from which the vertices are taken
     * @param source    the <code>NumberVertexValue</code> from which values are to be copied
     * @param dest      the <code>NumberVertexValue</code> into which values are to be copied
     */
    public static void copyValues(ArchetypeGraph g, NumberVertexValue source, NumberVertexValue dest) {
        for (Iterator iter = g.getVertices().iterator(); iter.hasNext();) {
            ArchetypeVertex v = (ArchetypeVertex) iter.next();
            dest.setNumber(v, source.getNumber(v));
        }
    }

    /**
     * Returns the <code>VertexGenerator</code>, if any, stored in <code>g</code>'s
     * user data at the standardized location specified by the VG interface: <code>VertexGenerator.TAG</code>.
     */
    public static VertexGenerator getVertexGenerator(ArchetypeGraph g) {
        return (VertexGenerator) g.getUserDatum(VertexGenerator.TAG);
    }

    /**
     * Converts <code>vertex_values</code> (a Map of vertex to Number values)
     * to a DoubleArrayList, using <code>indexer</code> to determine the location
     * of each vertex's value in the DAL.  
     * <b>Note</b>: assumes that <code>indexer</code> is 0-based and covers
     * all the vertices in <code>vertex_values</code>, and that 
     * <code>vertex_values</code> contains <code>Number</code> instances.
     * @param vertex_values a map of vertices to <code>Number</code> instances
     * @param indexer a 0-based index of the vertices
     * @return
     */
    public static DoubleArrayList vertexMapToDAL(Map vertex_values, Indexer indexer) {
        DoubleArrayList dal = new DoubleArrayList(vertex_values.size());
        // fill dal with "blank" elements
        dal.setSize(vertex_values.size());

        for (Iterator iter = vertex_values.keySet().iterator(); iter.hasNext();) {
            ArchetypeVertex av = (ArchetypeVertex) iter.next();
            double value = ((Number) vertex_values.get(av)).doubleValue();
            dal.set(indexer.getIndex(av), value);
        }

        return dal;
    }

    /**
     * Adds all vertices in the specified set to <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.addVertex</code> on all elements
     * of the set.
     * If any element of <code>vertices</code> may not be legally added
     * to this graph, throws an exception: <code>ClassCastException</code> if
     * the type is inappropriate, and <code>IllegalArgumentException</code>  
     * otherwise.  If an exception is thrown, any vertices that may 
     * already have been added are not guaranteed to be retained.
     */
    public static void addVertices(Graph g, Set vertices) {
        for (Iterator iter = vertices.iterator(); iter.hasNext();)
            g.addVertex((Vertex) iter.next());
    }

    /**
     * Adds all vertices in the specified set to <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.addVertex</code> on all elements
     * of the set.
     * If any element of <code>vertices</code> may not be legally added
     * to this graph, throws an exception: <code>ClassCastException</code> if
     * the type is inappropriate, and <code>IllegalArgumentException</code>  
     * otherwise.  If an exception is thrown, any vertices that may 
     * already have been added are not guaranteed to be retained.
     */
    public static void addVertices(Hypergraph g, Set vertices) {
        for (Iterator iter = vertices.iterator(); iter.hasNext();)
            g.addVertex((Hypervertex) iter.next());
    }

    /**
     * Adds all edges in the specified set to <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.addEdge</code> on all elements
     * of the set.
     * If any element of <code>edges</code> may not be legally added
     * to this graph, throws an exception: <code>ClassCastException</code> if
     * the type is inappropriate, and <code>IllegalArgumentException</code>  
     * otherwise.  If an exception is thrown, any edges that may 
     * already have been added are not guaranteed to be retained.
     */
    public static void addEdges(Graph g, Set edges) {
        for (Iterator iter = edges.iterator(); iter.hasNext();)
            g.addEdge((Edge) iter.next());
    }

    /**
     * Adds all edges in the specified set to <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.addEdge</code> on all elements
     * of the set.
     * If any element of <code>edges</code> may not be legally added
     * to this graph, throws an exception: <code>ClassCastException</code> if
     * the type is inappropriate, and <code>IllegalArgumentException</code>  
     * otherwise.  If an exception is thrown, any edges that may 
     * already have been added are not guaranteed to be retained.
     */
    public static void addEdges(Hypergraph g, Set edges) {
        for (Iterator iter = edges.iterator(); iter.hasNext();)
            g.addEdge((Hyperedge) iter.next());
    }

    /**
     * Removes all vertices in the specified set from <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.removeVertex</code> on all elements
     * of the set.
     * If any element of <code>vertices</code> is not part of this graph,
     * then throws <code>IllegalArgumentException</code>.  If this 
     * exception is thrown, any vertices that may have been removed already 
     * are not guaranteed to be restored to the graph.     
     */
    public static void removeVertices(Graph g, Set vertices) {
        for (Iterator iter = new LinkedList(vertices).iterator(); iter.hasNext();)
            g.removeVertex((Vertex) iter.next());
    }

    /**
     * Removes all vertices in the specified set from <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.removeVertex</code> on all elements
     * of the set.
     * If any element of <code>vertices</code> is not part of this graph,
     * then throws <code>IllegalArgumentException</code>.  If this 
     * exception is thrown, any vertices that may have been removed already 
     * are not guaranteed to be restored to the graph.     
     */
    public static void removeVertices(Hypergraph g, Set vertices) {
        for (Iterator iter = new LinkedList(vertices).iterator(); iter.hasNext();)
            g.removeVertex((Hypervertex) iter.next());
    }

    /**
     * Removes all vertices in the specified set from <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.removeVertex</code> on all elements
     * of the set.
     * If any element of <code>edges</code> is not part of this graph,
     * then throws <code>IllegalArgumentException</code>.  If this 
     * exception is thrown, any edges that may have been removed already 
     * are not guaranteed to be restored to the graph.  
     */
    public static void removeEdges(Graph g, Set edges) {
        for (Iterator iter = new LinkedList(edges).iterator(); iter.hasNext();)
            g.removeEdge((Edge) iter.next());
    }

    /**
     * Removes all vertices in the specified set from <code>g</code>. Syntactic
     * sugar for a loop that calls <code>g.removeVertex</code> on all elements
     * of the set.
     * If any element of <code>edges</code> is not part of this graph,
     * then throws <code>IllegalArgumentException</code>.  If this 
     * exception is thrown, any edges that may have been removed already 
     * are not guaranteed to be restored to the graph.  
     */
    public static void removeEdges(Hypergraph g, Set edges) {
        for (Iterator iter = new LinkedList(edges).iterator(); iter.hasNext();)
            g.removeEdge((Hyperedge) iter.next());
    }

}