edu.uci.ics.jung.graph.DirectedSparseHypergraph.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.graph.DirectedSparseHypergraph.java

Source

/*
 * Created on Feb 4, 2007
 *
 * Copyright (c) 2007, The JUNG Authors
 *
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either
 * "license.txt" or
 * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 */
package edu.uci.ics.jung.graph;

import com.google.common.base.Supplier;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import edu.uci.ics.jung.graph.util.EdgeType;
import edu.uci.ics.jung.graph.util.Pair;

import java.util.*;

/**
 * An implementation of <code>Hypergraph</code> that is suitable for sparse graphs and does not permits parallel edges.
 */
@SuppressWarnings("serial")
public class DirectedSparseHypergraph<V, E> extends AbstractTypedHypergraph<V, E>
        implements DirectedHypergraph<V, E> {

    protected Map<V, Pair<Multimap<V, E>>> vertices; // Map of vertices to incident hyperedge sets {incoming, outgoing}
    protected Map<E, Pair<Set<V>>> edges; // Map of hyperedges to incident vertex sets {head, tail}

    /**
     * Creates a <code>DirectedSparseHypergraph</code> and initializes the internal data structures.
     */
    public DirectedSparseHypergraph() {
        super(EdgeType.DIRECTED);
        vertices = new HashMap<V, Pair<Multimap<V, E>>>();
        edges = new HashMap<E, Pair<Set<V>>>();
    }

    /**
     * Returns a <code>Factory</code> which creates instances of this class.
     *
     * @param <V> vertex type of the hypergraph to be created
     * @param <E> edge type of the hypergraph to be created
     * @return a <code>Factory</code> which creates instances of this class
     */
    public static <V, E> Supplier<Hypergraph<V, E>> getFactory() {
        return new Supplier<Hypergraph<V, E>>() {
            @Override
            public Hypergraph<V, E> get() {
                return new DirectedSparseHypergraph<V, E>();
            }
        };
    }

    /**
     * Adds <code>hyperedge</code> to this graph and connects them to the vertex collection <code>endpoints</code>.
     * Any vertices in <code>endpoints</code> that appear more than once will only appear once in the
     * incident vertex collection for <code>hyperedge</code>, that is, duplicates will be ignored.
     *
     * @see Hypergraph#addEdge(Object, Collection)
     */
    @Override
    public boolean addEdge(E hyperedge, Collection<? extends V> endpoints, EdgeType edgeType) {
        this.validateEdgeType(edgeType);

        if (hyperedge == null)
            throw new IllegalArgumentException("input hyperedge may not be null");

        if (endpoints == null)
            throw new IllegalArgumentException("endpoints may not be null");

        if (endpoints.contains(null))
            throw new IllegalArgumentException("cannot add an edge with a null endpoint");

        if (endpoints.size() == 2) { //src->dest
            Iterator<? extends V> it = endpoints.iterator();
            V v1 = it.next();
            V v2 = it.next();
            return addEdge(hyperedge, Sets.newHashSet(v1), Sets.newHashSet(v2), edgeType);
        } else if (endpoints.size() == 1) { //1 vertex loop
            V v = endpoints.iterator().next();
            Set<V> vset = new HashSet<V>();
            vset.add(v);
            return addEdge(hyperedge, vset, vset, edgeType);
        } else if (endpoints.size() > 2) { //n vertex loop
            Set<V> vs = Sets.newHashSet(endpoints);
            return addEdge(hyperedge, vs, vs, edgeType);
        } else {
            throw new IllegalArgumentException(
                    "Graph objects connect 1 or 2 vertices; vertices arg has " + endpoints.size());
        }
    }

    public boolean addEdge(E edge, Set<? extends V> source, Set<? extends V> dest) {
        return addEdge(edge, source, dest, this.getDefaultEdgeType());
    }

    public boolean addEdge(E hyperedge, Set<? extends V> source, Set<? extends V> dest, EdgeType edgeType) {
        this.validateEdgeType(edgeType);

        if (hyperedge == null)
            throw new IllegalArgumentException("input hyperedge may not be null");

        if (source == null || dest == null)
            throw new IllegalArgumentException("endpoints may not be null");

        if (source.contains(null) || source.contains(null))
            throw new IllegalArgumentException("cannot add an edge with a null endpoint");

        Set<V> sourceSet = new HashSet<V>(source);
        Set<V> destSet = new HashSet<V>(dest);

        if (edges.containsKey(hyperedge)) {
            Pair<Set<V>> attached = edges.get(hyperedge);
            if (!attached.getFirst().equals(sourceSet) || !attached.getSecond().equals(destSet)) {
                throw new IllegalArgumentException(
                        "Edge " + hyperedge + " exists in this graph with endpoints " + attached);
            } else
                return false;
        }

        Pair<Set<V>> new_endpoints = new Pair<Set<V>>(sourceSet, destSet);
        edges.put(hyperedge, new_endpoints);

        for (V s : sourceSet) {
            // add v if it's not already in the graph
            if (!vertices.containsKey(s))
                this.addVertex(s);
        }
        for (V d : destSet) {
            // add v if it's not already in the graph
            if (!vertices.containsKey(d))
                this.addVertex(d);
        }

        // map source of this edge to <dest, edge> and vice versa
        for (V s : sourceSet) {
            Multimap<V, E> sourceOut = vertices.get(s).getSecond();
            for (V d : destSet) {
                sourceOut.put(d, hyperedge);
            }
        }
        for (V d : destSet) {
            Multimap<V, E> destIn = vertices.get(d).getFirst();
            for (V s : sourceSet) {
                destIn.put(s, hyperedge);
            }
        }
        return true;
    }

    @Override
    public boolean addVertex(V vertex) {
        if (vertex == null)
            throw new IllegalArgumentException("cannot add a null vertex");
        if (containsVertex(vertex))
            return false;
        Multimap<V, E> in = HashMultimap.create();
        Multimap<V, E> out = HashMultimap.create();
        vertices.put(vertex, new Pair<Multimap<V, E>>(in, out));
        return true;
    }

    @Override
    public boolean containsEdge(E edge) {
        return edges.keySet().contains(edge);
    }

    @Override
    public boolean containsVertex(V vertex) {
        return vertices.keySet().contains(vertex);
    }

    @Override
    public E findEdge(V v1, V v2) {
        if (!containsVertex(v1) || !containsVertex(v2))
            return null;

        for (E h : getIncidentEdges(v1)) {
            if (isIncident(v2, h))
                return h;
        }
        return null;
    }

    @Override
    public Collection<E> findEdgeSet(V v1, V v2) {
        if (!containsVertex(v1) || !containsVertex(v2))
            return null;

        Collection<E> edges = new ArrayList<E>();
        for (E h : getIncidentEdges(v1)) {
            if (isIncident(v2, h))
                edges.add(h);
        }
        return Collections.unmodifiableCollection(edges);
    }

    @Deprecated
    @Override
    public V getDest(E directed_edge) {
        return null;
    }

    @Override
    public int getEdgeCount() {
        return edges.size();
    }

    @Override
    public Collection<E> getEdges() {
        return Collections.unmodifiableCollection(edges.keySet());
    }

    @Override
    public Collection<V> getEndpoints(E edge) {
        if (!containsEdge(edge))
            return null;

        Pair<Set<V>> tmp = edges.get(edge);
        Set<V> endpoints = Sets.newHashSet();
        endpoints.addAll(tmp.getFirst());
        endpoints.addAll(tmp.getSecond());
        return Collections.unmodifiableCollection(endpoints);
    }

    @Override
    public Collection<V> getOpposite(V vertex, E edge) {
        if (!containsEdge(edge))
            return null;

        Pair<Set<V>> endpoints = edges.get(edge);

        boolean found = true;
        if (!endpoints.getFirst().contains(vertex)) {
            found = false;
        } else {
            return endpoints.getSecond();
        }
        if (!endpoints.getSecond().contains(vertex) && !found) {
            throw new IllegalArgumentException(vertex + " is not incident to " + edge + " in this graph");
        } else {
            return endpoints.getFirst();
        }
    }

    public Collection<V> getSourceSet(E edge) {
        if (!containsEdge(edge))
            return null;
        return edges.get(edge).getFirst();
    }

    public Collection<V> getDestSet(E edge) {
        if (!containsEdge(edge))
            return null;
        return edges.get(edge).getSecond();
    }

    @Override
    public Collection<E> getInEdges(V vertex) {
        if (!containsVertex(vertex))
            return null;
        return Collections.unmodifiableCollection(getIncoming_internal(vertex));
    }

    @Override
    public int getIncidentCount(E edge) {
        if (!containsEdge(edge))
            return 0;
        return edges.get(edge).size();
    }

    @Override
    public Collection<E> getIncidentEdges(V vertex) {
        if (!containsVertex(vertex))
            return null;

        Set<E> incident_edges = new HashSet<E>();
        incident_edges.addAll(getIncoming_internal(vertex));
        incident_edges.addAll(getOutgoing_internal(vertex));
        return Collections.unmodifiableCollection(incident_edges);
    }

    protected Collection<E> getIncoming_internal(V vertex) {
        return Sets.newHashSet(vertices.get(vertex).getFirst().values());
    }

    @Override
    public Collection<V> getNeighbors(V vertex) {
        if (!containsVertex(vertex))
            return null;

        Set<V> neighbors = Sets.newHashSet();
        neighbors.addAll(getPreds_internal(vertex));
        neighbors.addAll(getSuccs_internal(vertex));
        return Collections.unmodifiableCollection(neighbors);
    }

    @Override
    public Collection<E> getOutEdges(V vertex) {
        if (!containsVertex(vertex))
            return null;
        return Collections.unmodifiableCollection(getOutgoing_internal(vertex));
    }

    protected Collection<E> getOutgoing_internal(V vertex) {
        return Sets.newHashSet(vertices.get(vertex).getSecond().values());
    }

    @Override
    public Collection<V> getPredecessors(V vertex) {
        if (!containsVertex(vertex))
            return null;
        return Collections.unmodifiableCollection(getPreds_internal(vertex));
    }

    protected Collection<V> getPreds_internal(V vertex) {
        return Sets.newHashSet(vertices.get(vertex).getFirst().keySet());
    }

    @Deprecated
    @Override
    public V getSource(E directed_edge) {
        return null;
    }

    @Override
    public Collection<V> getSuccessors(V vertex) {
        if (!containsVertex(vertex))
            return null;
        return Collections.unmodifiableCollection(getSuccs_internal(vertex));
    }

    protected Collection<V> getSuccs_internal(V vertex) {
        return Sets.newHashSet(vertices.get(vertex).getSecond().keySet());
    }

    @Override
    public int getVertexCount() {
        return vertices.size();
    }

    @Override
    public Collection<V> getVertices() {
        return vertices.keySet();
    }

    @Override
    public boolean removeEdge(E edge) {
        if (!containsEdge(edge))
            return false;

        Collection<V> sourceSet = getSourceSet(edge);
        Collection<V> destSet = getDestSet(edge);

        // remove vertices from each others' adjacency maps
        for (V source : sourceSet) {
            Multimap<V, E> sourceOut = vertices.get(source).getSecond();
            for (V dest : destSet) {
                sourceOut.remove(dest, edge);
            }
        }
        for (V dest : destSet) {
            Multimap<V, E> destIn = vertices.get(dest).getFirst();
            for (V source : sourceSet) {
                destIn.remove(source, edge);
            }
        }

        edges.remove(edge);
        return true;
    }

    @Override
    public boolean removeVertex(V vertex) {
        if (!containsVertex(vertex))
            return false;

        // copy to avoid concurrent modification in removeEdge
        ArrayList<E> incident = new ArrayList<E>(getIncoming_internal(vertex));
        incident.addAll(getOutgoing_internal(vertex));

        for (E edge : incident)
            removeEdge(edge);

        vertices.remove(vertex);

        return true;
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer("Vertices:\n");
        for (V v : getVertices()) {
            sb.append(v + ",");
        }
        sb.setLength(sb.length() - 1);
        sb.append("\nEdges:\n");
        for (E e : getEdges()) {
            Collection<V> sourceSet = getSourceSet(e);
            Collection<V> destSet = getDestSet(e);
            sb.append(e + "" + Arrays.deepToString(sourceSet.toArray()) + " -> "
                    + Arrays.deepToString(destSet.toArray()) + "\n");
        }
        return sb.toString();
    }
}