edu.uci.ics.jung.algorithms.transformation.FoldingTransformerFixed.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.algorithms.transformation.FoldingTransformerFixed.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 Apr 21, 2004
 */
package edu.uci.ics.jung.algorithms.transformation;

import java.util.ArrayList;
import java.util.Collection;

import org.apache.commons.collections15.Factory;
import org.apache.commons.collections15.Predicate;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Hypergraph;
import edu.uci.ics.jung.graph.KPartiteGraph;
import edu.uci.ics.jung.graph.UndirectedGraph;
import edu.uci.ics.jung.graph.util.Pair;

/**
 * Methods for creating a "folded" graph based on a k-partite graph or a
 * hypergraph.  
 * 
 * <p>A "folded" graph is derived from a k-partite graph by identifying
 * a partition of vertices which will become the vertices of the new graph, copying
 * these vertices into the new graph, and then connecting those vertices whose
 * original analogues were connected indirectly through elements
 * of other partitions.</p>
 * 
 * <p>A "folded" graph is derived from a hypergraph by creating vertices based on
 * either the vertices or the hyperedges of the original graph, and connecting 
 * vertices in the new graph if their corresponding vertices/hyperedges share a 
 * connection with a common hyperedge/vertex.</p>   
 * 
 * @author Danyel Fisher
 * @author Joshua O'Madadhain
 */
public class FoldingTransformerFixed<V, E> {

    /**
     * Converts <code>g</code> into a unipartite graph whose vertex set is the
     * vertices of <code>g</code>'s partition <code>p</code>.  For vertices
     * <code>a</code> and <code>b</code> in this partition, the resultant
     * graph will include the edge <code>(a,b)</code> if the original graph
     * contains edges <code>(a,c)</code> and <code>(c,b)</code> for at least
     * one vertex <code>c</code>.
     * 
     * <p>The vertices of the new graph are the same as the vertices of the
     * appropriate partition in the old graph; the edges in the new graph are
     * created by the input edge <code>Factory</code>.</p>
     * 
     * <p>If there is more than 1 such vertex <code>c</code> for a given pair
     * <code>(a,b)</code>, the type of the output graph will determine whether
     * it will contain parallel edges or not.</p>
     * 
     * <p>This function will not create self-loops.</p>
     * 
     * @param <V> vertex type
     * @param <E> input edge type
     * @param g input k-partite graph
     * @param p predicate specifying vertex partition
     * @param graph_factory factory used to create the output graph 
     * @param edge_factory factory used to create the edges in the new graph
     * @return a copy of the input graph folded with respect to the input partition
     */
    public static <V, E> Graph<V, E> foldKPartiteGraph(KPartiteGraph<V, E> g, Predicate<V> p,
            Factory<Graph<V, E>> graph_factory, Factory<E> edge_factory) {
        Graph<V, E> newGraph = graph_factory.create();

        // get vertices for the specified partition
        Collection<V> vertices = g.getVertices(p);
        for (V v : vertices) {
            newGraph.addVertex(v);
            for (V s : g.getSuccessors(v)) {
                for (V t : g.getSuccessors(s)) {
                    if (!vertices.contains(t) || t.equals(v))
                        continue;
                    newGraph.addVertex(t);
                    newGraph.addEdge(edge_factory.create(), v, t);
                }
            }
        }
        return newGraph;
    }

    /**
     * Converts <code>g</code> into a unipartite graph whose vertices are the
     * vertices of <code>g</code>'s partition <code>p</code>, and whose edges
     * consist of collections of the intermediate vertices from other partitions.  
     * For vertices
     * <code>a</code> and <code>b</code> in this partition, the resultant
     * graph will include the edge <code>(a,b)</code> if the original graph
     * contains edges <code>(a,c)</code> and <code>(c,b)</code> for at least
     * one vertex <code>c</code>.
     * 
     * <p>The vertices of the new graph are the same as the vertices of the
     * appropriate partition in the old graph; the edges in the new graph are
     * collections of the intermediate vertices <code>c</code>.</p>
     * 
     * <p>This function will not create self-loops.</p>
     * 
     * @param <V> vertex type
     * @param <E> input edge type
     * @param g input k-partite graph
     * @param p predicate specifying vertex partition
     * @param graph_factory factory used to create the output graph 
     * @return the result of folding g into unipartite graph whose vertices
     * are those of the <code>p</code> partition of g
     */
    public static <V, E> Graph<V, Collection<V>> foldKPartiteGraph(KPartiteGraph<V, E> g, Predicate<V> p,
            Factory<Graph<V, Collection<V>>> graph_factory) {
        Graph<V, Collection<V>> newGraph = graph_factory.create();

        // get vertices for the specified partition, copy into new graph
        Collection<V> vertices = g.getVertices(p);

        for (V v : vertices) {
            newGraph.addVertex(v);
            for (V s : g.getSuccessors(v)) {
                for (V t : g.getSuccessors(s)) {
                    if (!vertices.contains(t) || t.equals(v))
                        continue;
                    newGraph.addVertex(t);
                    Collection<V> v_coll = newGraph.findEdge(v, t);
                    if (v_coll == null) {
                        v_coll = new ArrayList<V>();
                        newGraph.addEdge(v_coll, v, t);
                    }
                    v_coll.add(s);
                }
            }
        }
        return newGraph;
    }

    /**
     * Creates a <code>Graph</code> which is an edge-folded version of <code>h</code>, where
     * hyperedges are replaced by k-cliques in the output graph.
     * 
     * <p>The vertices of the new graph are the same objects as the vertices of 
     * <code>h</code>, and <code>a</code> 
     * is connected to <code>b</code> in the new graph if the corresponding vertices
     * in <code>h</code> are connected by a hyperedge.  Thus, each hyperedge with 
     * <i>k</i> vertices in <code>h</code> induces a <i>k</i>-clique in the new graph.</p>
     * 
     * <p>The edges of the new graph consist of collections of each hyperedge that connected
     * the corresponding vertex pair in the original graph.</p>
     * 
     * @param <V> vertex type
     * @param <E> input edge type
     * @param h hypergraph to be folded
     * @param graph_factory factory used to generate the output graph
     * @return a copy of the input graph where hyperedges are replaced by cliques
     */
    public static <V, E> UndirectedGraph<V, FoldedEdge<V, E>> foldHypergraphEdges(Hypergraph<V, E> h,
            Factory<UndirectedGraph<V, FoldedEdge<V, E>>> graph_factory) {
        UndirectedGraph<V, FoldedEdge<V, E>> target = graph_factory.create();

        for (V v : h.getVertices())
            target.addVertex(v);

        for (E e : h.getEdges()) {
            ArrayList<V> incident = new ArrayList<V>(h.getIncidentVertices(e));
            populateTarget(target, e, incident);
        }
        return target;
    }

    /**
     * Creates a <code>Graph</code> which is an edge-folded version of <code>h</code>, where
     * hyperedges are replaced by k-cliques in the output graph.
     * 
     * <p>The vertices of the new graph are the same objects as the vertices of 
     * <code>h</code>, and <code>a</code> 
     * is connected to <code>b</code> in the new graph if the corresponding vertices
     * in <code>h</code> are connected by a hyperedge.  Thus, each hyperedge with 
     * <i>k</i> vertices in <code>h</code> induces a <i>k</i>-clique in the new graph.</p>
     * 
     * <p>The edges of the new graph are generated by the specified edge factory.</p>
     * 
     * @param <V> vertex type
     * @param <E> input edge type
     * @param h hypergraph to be folded
     * @param graph_factory factory used to generate the output graph
     * @param edge_factory factory used to create the new edges 
     * @return a copy of the input graph where hyperedges are replaced by cliques
     */
    public static <V, E> UndirectedGraph<V, E> foldHypergraphEdges(Hypergraph<V, E> h,
            Factory<UndirectedGraph<V, E>> graph_factory, Factory<E> edge_factory) {
        UndirectedGraph<V, E> target = graph_factory.create();

        for (V v : h.getVertices())
            target.addVertex(v);

        for (E e : h.getEdges()) {
            ArrayList<V> incident = new ArrayList<V>(h.getIncidentVertices(e));
            for (int i = 0; i < incident.size(); i++)
                for (int j = i + 1; j < incident.size(); j++)
                    target.addEdge(edge_factory.create(), incident.get(i), incident.get(j));
        }
        return target;
    }

    /**
     * Creates a <code>Graph</code> which is a vertex-folded version of <code>h</code>, whose
     * vertices are the input's hyperedges and whose edges are induced by adjacent hyperedges
     * in the input.
     * 
     * <p>The vertices of the new graph are the same objects as the hyperedges of 
     * <code>h</code>, and <code>a</code> 
     * is connected to <code>b</code> in the new graph if the corresponding edges
     * in <code>h</code> have a vertex in common.  Thus, each vertex incident to  
     * <i>k</i> edges in <code>h</code> induces a <i>k</i>-clique in the new graph.</p>
     * 
     * <p>The edges of the new graph are created by the specified factory.</p>
     * 
     * @param <V> vertex type
     * @param <E> input edge type
     * @param <F> output edge type
     * @param h hypergraph to be folded
     * @param graph_factory factory used to generate the output graph
     * @param edge_factory factory used to generate the output edges
     * @return a transformation of the input graph whose vertices correspond to the input's hyperedges 
     * and edges are induced by hyperedges sharing vertices in the input
     */
    public static <V, E, F> UndirectedGraph<E, F> foldHypergraphVertices(Hypergraph<V, E> h,
            Factory<UndirectedGraph<E, F>> graph_factory, Factory<F> edge_factory) {
        UndirectedGraph<E, F> target = graph_factory.create();

        for (E e : h.getEdges())
            target.addVertex(e);

        for (V v : h.getVertices()) {
            ArrayList<E> incident = new ArrayList<E>(h.getIncidentEdges(v));
            for (int i = 0; i < incident.size(); i++)
                for (int j = i + 1; j < incident.size(); j++)
                    target.addEdge(edge_factory.create(), incident.get(i), incident.get(j));
        }

        return target;
    }

    /**
     * Creates a <code>Graph</code> which is a vertex-folded version of <code>h</code>, whose
     * vertices are the input's hyperedges and whose edges are induced by adjacent hyperedges
     * in the input.
     * 
     * <p>The vertices of the new graph are the same objects as the hyperedges of 
     * <code>h</code>, and <code>a</code> 
     * is connected to <code>b</code> in the new graph if the corresponding edges
     * in <code>h</code> have a vertex in common.  Thus, each vertex incident to  
     * <i>k</i> edges in <code>h</code> induces a <i>k</i>-clique in the new graph.</p>
     * 
     * <p>The edges of the new graph consist of collections of each vertex incident to 
     * the corresponding hyperedge pair in the original graph.</p>
     * 
     * @param h hypergraph to be folded
     * @param graph_factory factory used to generate the output graph
     * @return a transformation of the input graph whose vertices correspond to the input's hyperedges 
     * and edges are induced by hyperedges sharing vertices in the input
     */
    public UndirectedGraph<E, FoldedEdge<E, V>> foldHypergraphVertices(Hypergraph<V, E> h,
            Factory<UndirectedGraph<E, FoldedEdge<E, V>>> graph_factory) {
        UndirectedGraph<E, FoldedEdge<E, V>> target = graph_factory.create();

        for (E e : h.getEdges())
            target.addVertex(e);

        for (V v : h.getVertices()) {
            ArrayList<E> incident = new ArrayList<E>(h.getIncidentEdges(v));
            populateTarget(target, v, incident);
        }
        return target;
    }

    /**
     * @param target
     * @param e
     * @param incident
     */
    private static <S, T> void populateTarget(UndirectedGraph<S, FoldedEdge<S, T>> target, T e,
            ArrayList<S> incident) {
        for (int i = 0; i < incident.size(); i++) {
            S v1 = incident.get(i);
            for (int j = i + 1; j < incident.size(); j++) {
                S v2 = incident.get(j);
                FoldedEdge<S, T> e_coll = target.findEdge(v1, v2);
                if (e_coll == null) {
                    e_coll = new FoldedEdge<S, T>(v1, v2);
                    target.addEdge(e_coll, v1, v2);
                }
                e_coll.getFolded().add(e);
            }
        }
    }

    /**
     * An edge resulting from folding on a Hypergraph.
     */
    public static class FoldedEdge<V, E> {
        private Pair<V> d_vertices;
        private Collection<E> d_folded;

        /**
         * The FoldedEdge is identified by it's pair of vertices, since the
         * set of folded objects it corresponds to need not be unique. 
         */
        public FoldedEdge(V v1, V v2) {
            d_vertices = new Pair<V>(v1, v2);
            d_folded = new ArrayList<E>();
        }

        /**
         * @return The vertices incident with this edge.
         */
        public Pair<V> getVertices() {
            return d_vertices;
        }

        /**
         * @return The Collection of objects that were folded onto this edge.
         */
        public Collection<E> getFolded() {
            return d_folded;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof FoldedEdge<?, ?>) {
                FoldedEdge<?, ?> other = (FoldedEdge<?, ?>) obj;
                return other.d_vertices.equals(d_vertices);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return d_vertices.hashCode();
        }
    }
}