edu.uci.ics.jung.graph.impl.BipartiteGraph.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.graph.impl.BipartiteGraph.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 Aug 6, 2003
 */
package edu.uci.ics.jung.graph.impl;

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.collections.MultiHashMap;
import org.apache.commons.collections.MultiMap;

import edu.uci.ics.jung.exceptions.FatalException;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.utils.GraphUtils;
import edu.uci.ics.jung.utils.UserData;

/**
 * A Bipartite graph is divided into A vertices and B vertices. Edges
 * only connect A vertices to B vertices, and vice versa. This class
 * extends <i>UndirectedSparseGraph</i>; thus, the Graph is made up of
 * <i>UndirectedSparseVertices</i>. <p>
 * Vertices can only be added to the graph with a flag that says
 * which class they will be added to (using <i>BipartiteGraph.Choice</i> );
 * edges must be of type <i>BipartiteGraph</i>, which must consist of two 
 * vertices, one each from CLASSA and CLASSB. 
 * <pre>
 * BipartiteGraph bpg = new BipartiteGraph;
 * Vertex va = bpg.addVertex( new UndirectedSparseVertex(), BipartiteGraph.CLASSA );
 * Vertex vb = bpg.addVertex( new UndirectedSparseVertex(), BipartiteGraph.CLASSB );
 * bpg.addBipartiteEdge( new BipartiteEdge( va, vb ));
 * </pre>
 * Note that the traditional <i>addVertex()</i> and <i>addEdge()</i> will
 * both throw a <i>FatalException</i>.<p>
 * The function <i>fold</i> creates an <i>UndirectedGraph</i>
 * based on finding vertices that share a common neighbor.
 * 
 * @author danyelf
 * @since 1.0.1
 */
public class BipartiteGraph extends UndirectedSparseGraph {

    private Set aSet = new HashSet();
    private Set bSet = new HashSet();

    public void initialize() {
        super.initialize();
        aSet = new HashSet();
        bSet = new HashSet();
    }

    /**
     * Returns the set of all vertices from that class. 
     * All vertices in the return set will be of class
     * A or class B, depending on the parameter.
     */
    public Set getAllVertices(Choice choice) {
        if (choice == CLASSA) {
            return Collections.unmodifiableSet(aSet);
        } else if (choice == CLASSB) {
            return Collections.unmodifiableSet(bSet);
        } else
            throw new IllegalArgumentException("Invalid partition specification " + choice);
    }

    //   public ArchetypeGraph copy() {
    //      System.out.println( this.getClass() );
    //      ArchetypeGraph c = newInstance();
    //      for (Iterator iter = getVertices().iterator(); iter.hasNext();) {
    //         ArchetypeVertex av = (ArchetypeVertex) iter.next();
    //         ArchetypeVertex avNew = av.copy(c);
    //      }
    //      for (Iterator iter = getEdges().iterator(); iter.hasNext();) {
    //         ArchetypeEdge ae = (ArchetypeEdge) iter.next();
    //         ae.copy(c);
    //      }
    //      c.importUserData(this);
    //      return c;
    //
    //   }

    /**
     * Returns the partition for vertex <code>v</code>.
     * @param v
     */
    public Choice getPartition(BipartiteVertex v) {
        if (aSet.contains(v))
            return CLASSA;
        else if (bSet.contains(v))
            return CLASSB;
        else {
            if (v.getGraph() == this)
                throw new IllegalArgumentException("Inconsistent state in graph!");
            throw new IllegalArgumentException("Vertex " + v + " is not part of this graph");
        }
    }

    /**
     * Adds a single vertex to the graph in the specified partition.
     * Note that the vertex must be compatible with BipartiteVertex.
     * 
      * <p>Throws an <code>IllegalArgumentException</code>
      * if <code>v</code> is not an element of either partition.</p>
      * 
     * @param v         the vertex to be added to the class
     * @param choice   the class to which the vertex should be added
     * @return the input vertex
     */
    public BipartiteVertex addVertex(BipartiteVertex v, Choice choice) {
        String exists = "Specified partition already contains vertex ";
        String dup = "Another partition already contains vertex ";
        if (choice == CLASSA) {
            if (aSet.contains(v))
                throw new IllegalArgumentException(exists + v);
            if (bSet.contains(v))
                throw new IllegalArgumentException(dup + v);
            aSet.add(v);
        } else if (choice == CLASSB) {
            if (bSet.contains(v))
                throw new IllegalArgumentException(exists + v);
            if (aSet.contains(v))
                throw new IllegalArgumentException(dup + v);
            bSet.add(v);
        } else
            throw new IllegalArgumentException("Invalid partition specification for vertex " + v + ": " + choice);
        super.addVertex(v);
        return v;
    }

    /**
     * Adds a BipartiteEdge to the Graph. This function is simply a 
     * typed version of addEdge
     * @param bpe a BipartiteEdge
     * @return the edge, now a member of the graph.
     */
    public BipartiteEdge addBipartiteEdge(BipartiteEdge bpe) {
        return (BipartiteEdge) super.addEdge(bpe);
    }

    /**
     * DO NOT USE THIS METHOD. Contractually required, but merely throws a FatalException. 
     * @see edu.uci.ics.jung.graph.impl.UndirectedSparseGraph#addEdge(edu.uci.ics.jung.graph.Edge)
     * @deprecated Use addBipartiteEdge
     */
    public Edge addEdge(Edge ae) {
        throw new FatalException("Only add BipartiteEdges");
    }

    /**
     * DO NOT USE THIS METHOD. Contractually required, but merely throws a FatalException. 
     * @see edu.uci.ics.jung.graph.impl.UndirectedSparseGraph#addVertex(edu.uci.ics.jung.graph.Vertex)
     * @deprecated Use addBipartiteVertex
     */
    public Vertex addVertex(Vertex av) {
        throw new FatalException("Use addVertexX to add vertices to a BipartiteGraph ");
    }

    /**
     * This small enumerated type merely forces a user to pick class "A"
     * or "B" when adding a Vertex to a BipartiteGraph.
     */
    public static final class Choice {
    }

    public static final Choice CLASSA = new Choice();
    public static final Choice CLASSB = new Choice();

    /**
     * Creates a one-part graph from a bipartite graph by folding
     * Vertices from one class into a second class. This function
     * creates a new UndirectedGraph (with vertex set V') in which: <br>
     * <ul>
     * <li> each vertex in V' has an equivalent V in bpg.getAllVertices( class ) </li>
     * <li> an edge E' joins V'1 and V'2 iff there is a path of length 2 from
     * V1 to V2 (by way of some third vertex in the other class, VXs) </li>
     * <li> each edge E' is annotated with the set of vertices VXs </li>
     * </ul>
     * 
     * In social network analysis and related fields, this operation transforms
     * an actor-by-event chart into an actor-by-actor chart.
     * 
     * @param bpg      The bipartite graph to be folded
     * @param vertexSet      Chooses the set of vertices to be brought into
     *                the new Graph.
     * @return   an UndirectedSparseGraph.
     */
    public static Graph fold(BipartiteGraph bpg, Choice vertexSet) {
        Graph newGraph = new UndirectedSparseGraph();
        Set vertices = bpg.getAllVertices(vertexSet);
        for (Iterator iter = vertices.iterator(); iter.hasNext();) {
            BipartiteVertex v = (BipartiteVertex) iter.next();
            v.copy(newGraph);
        }

        Set coveredNodes = new HashSet();

        for (Iterator iter = vertices.iterator(); iter.hasNext();) {
            BipartiteVertex v = (BipartiteVertex) iter.next();
            coveredNodes.add(v);

            // the set of all Bs that touch this A
            Set hyperEdges = v.getNeighbors();

            // this will ultimately contain a mapping from
            // the next adjacent "A" to the list of "B"s that support that
            // connection (that is, all Bs that run between this A and its neighbor
            MultiMap mm = new MultiHashMap();
            for (Iterator iterator = hyperEdges.iterator(); iterator.hasNext();) {
                Vertex hyperEdge = (Vertex) iterator.next();
                addAll(mm, hyperEdge.getNeighbors(), hyperEdge);
            }
            for (Iterator iterator = mm.keySet().iterator(); iterator.hasNext();) {
                Vertex aVertex = (Vertex) iterator.next();

                if (coveredNodes.contains(aVertex))
                    continue;

                Edge newEdge = GraphUtils.addEdge(newGraph, (Vertex) v.getEqualVertex(newGraph),
                        (Vertex) aVertex.getEqualVertex(newGraph));
                newEdge.addUserDatum(BIPARTITE_USER_TAG, mm.get(aVertex), UserData.SHARED);
            }
        }
        return newGraph;
    }

    /**
     * The tag for the UserData attached to a single Edge.
     */
    public static final Object BIPARTITE_USER_TAG = "BipartiteUserTag";

    /**
     * Adds all pairs (key, value) to the multimap from
     * the initial set keySet.
     * @param set
     * @param hyperEdge
     */
    private static void addAll(MultiMap mm, Set keyset, Object value) {
        for (Iterator iter = keyset.iterator(); iter.hasNext();) {
            Object key = iter.next();
            mm.put(key, value);
        }
    }

    /* (non-Javadoc)
     * @see edu.uci.ics.jung.graph.Graph#removeVertex(edu.uci.ics.jung.graph.Vertex)
     */
    public void removeVertex(Vertex v) {
        super.removeVertex(v);
        if (aSet.contains(v)) {
            aSet.remove(v);
        } else {
            bSet.remove(v);
        }
    }

}