Package edu.ucla.sspace.graph

Source Code of edu.ucla.sspace.graph.Subgraph$SubgraphNeighborsView$SubgraphNeighborsIterator

/*
* Copyright 2011 David Jurgens
*
* This file is part of the S-Space package and is covered under the terms and
* conditions therein.
*
* The S-Space package is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation and distributed hereunder to you.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND NO REPRESENTATIONS OR WARRANTIES,
* EXPRESS OR IMPLIED ARE MADE.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, WE MAKE
* NO REPRESENTATIONS OR WARRANTIES OF MERCHANT- ABILITY OR FITNESS FOR ANY
* PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE OR DOCUMENTATION
* WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER
* RIGHTS.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package edu.ucla.sspace.graph;

import java.lang.ref.WeakReference;

import java.util.AbstractSet;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Set;

import edu.ucla.sspace.util.CombinedIterator;

import edu.ucla.sspace.util.primitive.AbstractIntSet;
import edu.ucla.sspace.util.primitive.IntIterator;
import edu.ucla.sspace.util.primitive.IntSet;
import edu.ucla.sspace.util.primitive.PrimitiveCollections;
import edu.ucla.sspace.util.primitive.TroveIntSet;

import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;


/**
* A base class for many {@link Graph} implementations.  The core functionality
* of this class is provided by the {@link EdgeSet} instances returned by the
* subclass for specifying how edges are to be stored and which edges are valid.
* All calls to these sets are wrapped to ensure proper state is maintained by
* this {@code AbstractGraph} instance.
*
* <p> This class support all optional {@link Graph} methods provided that the
* {@link EdgeSet} implementations used by the subclass also support them.
* Furthermore, all methods that return non-empty collections of {@link Edge}
* instance can be used to modify the state of this graph by any of their
* respective mutation methods (e.g., adding or removing {@code Edge}
* instances).  In addition, changes to the set of vertices returned by {@link
* #vertices()} has the same effect as adding and removing vertices to this
* graph.  Subclasses that wish to avoid this behavior may override these calls
* and wrap this classes return value in a {@link
* Collections#unmodifiableSet(Set)}.
*
* @author David Jurgens
*/
public abstract class AbstractGraph<T extends Edge,S extends EdgeSet<T>>
        implements Graph<T>, java.io.Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * The default space allocated for storing vertices.
     */
    public static final int DEFAULT_INITIAL_VERTEX_CAPACITY = 16;

    /**
     * The number of edges in this graph.
     */
    private int numEdges;

    /**
     * A mapping from a vertex's index to the the set of {@link Edge} instances
     * that connect it to other members of the graph.
     */
    private final TIntObjectMap<S> vertexToEdges;

    /**
     * A collection of all the subgraphs that have been returned from this
     * graph.  This collection is necessary to inform subgraphs of any vertex
     * changes (removals) to this graph without requiring them to constantly
     * check for updates.  We use a {@link WeakReference} in order to keep track
     * of the canonical {@code Subgraph} instance while ensuring that it is
     * garbage collected when it is no longer referred to (which would never
     * happen if this list contained strong references).
     */
    private Collection<WeakReference<Subgraph>> subgraphs;

    /**
     * Creates an empty {@code AbstractGraph} with the default initial capacity
     * for vertices ({@value DEFAULT_INITIAL_VERTEX_CAPACITY});
     */
    public AbstractGraph() {
        this(DEFAULT_INITIAL_VERTEX_CAPACITY);
    }


    /**
     * Creates an empty {@code AbstractGraph} with the provided initial capacity
     */
    public AbstractGraph(int capacity) {
        if (capacity < 0)
            throw new IllegalArgumentException("Capcity must be positive");
       
        vertexToEdges = new TIntObjectHashMap<S>(capacity);
        subgraphs = new ArrayList<WeakReference<Subgraph>>();
    }   

    /**
     * Creates a new {@code AbstractGraph} with the provided set of vertices.
     */
    public AbstractGraph(Set<Integer> vertices) {
        this(Math.max(vertices.size(), DEFAULT_INITIAL_VERTEX_CAPACITY));
        for (Integer v : vertices)
            vertexToEdges.put(v, createEdgeSet(v));
    }   

    /**
     * Returns the {@link EdgeSet} for this vertex, adding the vertex to this
     * graph if abstent.
     */
    private EdgeSet<T> addIfAbsent(int v) {
        S edges = getEdgeSet(v);
        if (edges == null) {
            edges = createEdgeSet(v);
            vertexToEdges.put(v, edges);
        }
        return edges;
    }
       
    /**
     * {@inheritDoc}
     */
    public boolean add(int v) {
        S edges = getEdgeSet(v);
        if (edges == null) {
            edges = createEdgeSet(v);
            vertexToEdges.put(v, edges);
            return true;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public boolean add(T e) {
        EdgeSet<T> from = addIfAbsent(e.from());
        EdgeSet<T> to = addIfAbsent(e.to());

        // Add this edge for the vertex to which the edge is pointing.  This
        // double-add behavior is necessary to ensure that the EdgeSet for each
        // vertices contains all the edges that connect to that vertex.
        //
        // NOTE: having the double add outside of the isNew check is also
        // necessary to support changing the weights on a WeightedGraph, where
        // adding a duplicate edge with a different weight will change the
        // weight but not add a new edge (i.e., increase the size).
        boolean isNew = from.add(e);
        to.add(e);
        if (isNew)
            numEdges++;
       
        assert from.contains(e) : "error in EdgeSet contains logic";
        assert to.contains(e) : "error in EdgeSet contains logic";

        return isNew;
    }

    private void checkIndex(int vertex) {
        if (vertex < 0)
            throw new IllegalArgumentException("vertices must be non-negative");
    }

    /**
     * {@inheritDoc}
     */
    public void clear() {
        vertexToEdges.clear();
        numEdges = 0;
    }

    /**
     * {@inheritDoc}
     */
    public void clearEdges() {
        for (EdgeSet<T> e : vertexToEdges.valueCollection())
            e.clear();
        numEdges = 0;
    }

    /**
     * {@inheritDoc}
     */
    public boolean contains(int vertex) {
        return vertexToEdges.containsKey(vertex);
    }

    /**
     * {@inheritDoc}
     */
    public boolean contains(int vertex1, int vertex2) {
        EdgeSet<T> e1 = getEdgeSet(vertex1);
        return e1 != null && e1.connects(vertex2);
    }

    /**
     * {@inheritDoc}
     *
     * <p> This method is sensitive to the vertex ordering; a call will check
     * whether the edge set for {@code e.from()} contains {@code e}.  Subclasses
     * should override this method if their {@link EdgeSet} implementations are
     * sensitive to the ordering of the vertex indices, or if a more advanced
     * behavior is needed.
     */
    public boolean contains(Edge e) {
        EdgeSet<T> e1 = getEdgeSet(e.from());       
        return e1 != null && e1.contains(e);
    }

    /**
     * {@inheritDoc}
     */
    public abstract Graph<T> copy(Set<Integer> vertices);

    /**
     * Returns a {@link EdgeSet} that will be used to store the edges of the
     * specified vertex
     */
    protected abstract S createEdgeSet(int vertex);
   
    /**
     * {@inheritDoc}
     */
    public int degree(int vertex) {
        EdgeSet<T> e = getEdgeSet(vertex);
        return (e == null) ? 0 : e.size();
    }

    /**
     * {@inheritDoc}
     */
    public Set<T> edges() {
        return new EdgeView();
    }

    /**
     * {@inheritDoc}
     */
    @Override public boolean equals(Object o) {
        if (o instanceof Graph) {
            Graph<?> g = (Graph<?>)o;
            return g.order() == order()
                && g.size() == size()
                && g.vertices().equals(vertices())
                && g.edges().equals(edges());                   
        }
        return false;
    }
   
    /**
     * {@inheritDoc}
     */
    public Set<T> getAdjacencyList(int vertex) {
        EdgeSet<T> e = getEdgeSet(vertex);
        return (e == null)
            ? Collections.<T>emptySet()
            : new AdjacencyListView(e);
    }

    /**
     * {@inheritDoc}
     */
    public IntSet getNeighbors(int vertex) {
         EdgeSet<T> e = getEdgeSet(vertex);
         return (e == null)
             ? PrimitiveCollections.emptyIntSet()
             : PrimitiveCollections.unmodifiableSet(e.connected());
    }

    /**
     * {@inheritDoc}
     */
    public Set<T> getEdges(int vertex1, int vertex2) {
        EdgeSet<T> e = getEdgeSet(vertex1);
        if (e == null)
            return Collections.<T>emptySet();
        Set<T> edges = e.getEdges(vertex2);
        return edges.isEmpty() ? Collections.<T>emptySet() : edges;
    }

    /**
     * Returns the set of edges assocated with the vertex, or {@code null} if
     * this vertex is not in this graph.
     */
    protected S getEdgeSet(int vertex) {
        return vertexToEdges.get(vertex);
    }

    /**
     * {@inheritDoc}
     */
    public boolean hasCycles() {
        throw new UnsupportedOperationException("fix me");
    }

    /**
     * {@inheritDoc}
     */
    public int hashCode() {
        return vertices().hashCode();
    }

    /**
     * {@inheritDoc}
     */
    public Iterator<Integer> iterator() {
        return new VertexView().iterator();
    }
   
    /**
     * {@inheritDoc}
     */
    public int order() {
        return vertexToEdges.size();
    }

    /**
     * {@inheritDoc
     *
     * <p> This method is sensitive to the vertex ordering; a call will remove
     * the vertex for {@code e.to()} from the edge for {@code e.from()}.
     * Subclasses should override this method if their {@link EdgeSet}
     * implementations are sensitive to the ordering of the vertex indices, or
     * if a more advanced behavior is needed.
     */
    public boolean remove(Edge e) {
        EdgeSet<T> from = getEdgeSet(e.from());
        EdgeSet<T> to = getEdgeSet(e.to());
       
        int before = numEdges;
        if (from != null && from.remove(e)) {
            numEdges--;
            assert to.contains(e)
                : "Complementary edge set " + to + "  did not contain " + e;
            // Remove the edge from the EdgeSet for the vertex to which this
            // edge points.
            to.remove(e);
        }

        return before != numEdges;       
    }

    /**
     * {@inheritDoc}
     */
    public boolean remove(int vertex) {
        EdgeSet<T> edges = vertexToEdges.remove(vertex);
        if (edges == null)
            return false;
        // Call the internal remove method to perform the remaining
        // removal logic.
        removeInternal(vertex, edges);
        return true;
    }

    /**
     * Removes the edges of the provided vertex from this graph, accounting for
     * the presence of the edges in the corresponding {@link EdgeSet}'s for the
     * other vertex in each edge.  This method should only be called once a
     * vertex has been removed from the {@link #vertexToEdges} mapping.
     */
    private void removeInternal(int vertex, EdgeSet<T> edges) {
        // Discount all the edges that were stored in this vertices edge set
        numEdges -= edges.size();

        // Now find all the edges stored in other vertices that might point to
        // this vertex and remove them
        for (Edge e : edges) {
            // Identify the other vertex in the removed edge and remove the
            // edge from the vertex's corresponding EdgeSet.
            int otherVertex = (e.from() == vertex) ? e.to() : e.from();
            EdgeSet<T> otherEdges = vertexToEdges.get(otherVertex);
            assert otherEdges.contains(e)
                : "Error in ensuring consistent from/to edge sets";
            otherEdges.remove(e);           
        }

        // Update any of the subgraphs that had this vertex to notify them
        // that it was removed
        Iterator<WeakReference<Subgraph>> iter = subgraphs.iterator();
        while (iter.hasNext()) {
            WeakReference<Subgraph> ref = iter.next();
            Subgraph s = ref.get();
            // Check whether this subgraph was already gc'd (the subgraph
            // was no longer in use) and if so, remove the ref from the list
            // to avoid iterating over it again
            if (s == null) {
                iter.remove();
                continue;
            }

            // Remove the vertex from the subgraph
            s.vertexSubset.remove(vertex);
        }
    }
   
    /**
     * {@inheritDoc}
     */
    public int size() {
        return numEdges;
    }

    /**
     * {@inheritDoc}
     */
    public Graph<T> subgraph(Set<Integer> vertices) {
        Subgraph sub = new Subgraph(vertices);
        subgraphs.add(new WeakReference<Subgraph>(sub));
        return sub;
    }

    /**
     * Returns a description of the graph as the sequence of its edges.
     */
    public String toString() {
        // REMINDER: make this more efficient with a StringBuilder
        return "{ vertices: " + vertices() + ", edges: " + edges() + "}";
    }

    /**
     * {@inheritDoc}
     */
    public IntSet vertices() {
        return new VertexView();
//         // REMINDER: possibly make this mutable with the VertexView class
//         return PrimitiveCollections.unmodifiableSet(
//             TroveIntSet.wrap(vertexToEdges.keySet()));
    }

    /**
     * A view of this graph's vertices, which provides support for adding,
     * removing, and iterating.  This class implements all optional methods for
     * {@link Set} and {@link Iterator}.
     */
    private class VertexView extends AbstractIntSet {
       
        public VertexView() { }

        public boolean add(int vertex) {
            return AbstractGraph.this.add(vertex);
        }

        public boolean add(Integer vertex) {
            return AbstractGraph.this.add(vertex);
        }

        public boolean contains(int vertex) {
            return AbstractGraph.this.contains(vertex);
        }

        public boolean contains(Integer vertex) {
            return AbstractGraph.this.contains(vertex);
        }

        public IntIterator iterator() {
            return new VertexIterator();
        }

        public boolean remove(int i) {
            return AbstractGraph.this.remove(i);
        }

        public boolean remove(Integer i) {
            return AbstractGraph.this.remove(i);
        }

        public int size() {
            return order();
        }

        public class VertexIterator implements IntIterator {

            boolean alreadyRemoved = true;
            IntIterator iter;
            int cur;

            public VertexIterator() {
                iter = TroveIntSet.wrap(vertexToEdges.keySet()).iterator();
                cur = -1;
            }

            public boolean hasNext() {
                return iter.hasNext();
            }

            public int nextInt() {
                alreadyRemoved = false;
                cur = iter.nextInt();
                return cur;
            }

            public Integer next() {
                return nextInt();
            }

            public void remove() {
                if (alreadyRemoved)
                    throw new IllegalStateException();
                alreadyRemoved = true;
                AbstractGraph.this.remove(cur);
            }
        }
    }

    /**
     * A view for the {@code Edge} adjacency list of a vertex.  This class
     * monitors for changes to edge set to update the state of this graph
     */
    private class AdjacencyListView extends AbstractSet<T> {

        private final EdgeSet<T> adjacencyList;

        public AdjacencyListView(EdgeSet<T> adjacencyList) {           
            this.adjacencyList = adjacencyList;
        }

        /**
         * Adds an edge to this vertex and adds the vertex to the graph if it
         * was not present before.
         */
        @Override public boolean add(T edge) {
            // If we've added a new edge to this vertex's adjacency list, check
            // whether we've added a new vertex to the graph
            if (adjacencyList.add(edge)) {

                // Figure out which vertex was newly connected
                int otherVertex = (edge.from() == adjacencyList.getRoot())
                    ? edge.to() : edge.from();
                if (!vertexToEdges.containsKey(otherVertex)) {
                    AbstractGraph.this.add(otherVertex);
                }
                // Last, add this edge to the EdgeSet for the other vertex in
                // the edge
                vertexToEdges.get(otherVertex).add(edge);
                numEdges++;
                return true;
            }
            return false;
        }

        @Override public boolean contains(Object edge) {
            return adjacencyList.contains(edge);
        }

        public Iterator<T> iterator() {
            return new AdjacencyListIterator();
        }

        @Override public boolean remove(Object o) {
            if (!(o instanceof Edge))
                return false;
            Edge edge = (Edge)o;
            // If the vertex was successfully removed, we need to remove the
            // edge from the edge set for the other vertex in the edge
            if (adjacencyList.remove(edge)) {
                // Determine the non-root vertex in the edge
                int otherVertex = (edge.from() == adjacencyList.getRoot())
                    ? edge.to() : edge.from();
                // Then remove the edge from its adjacency list as well
                vertexToEdges.get(otherVertex).remove(edge);

                numEdges--;
                return true;
            }
            return false;
        }

        public int size() {
            return adjacencyList.size();
        }

        /**
         * A decorator around the iterator for an adjacency list, which tracks
         * edges removal to update the number of edges in the graph.
         */
        private class AdjacencyListIterator implements Iterator<T> {

            private final Iterator<T> edges;

            public AdjacencyListIterator() {
                edges = adjacencyList.iterator();
            }

            public boolean hasNext() {
                return edges.hasNext();
            }

            public T next() {
                return edges.next();
            }

            public void remove() {
                edges.remove();
                numEdges--;
            }           
        }

    }

    /**
     * A view of a vertex's adjacencent vertices that monitors for additions and
     * removals to the set in order to update the state of this {@code Graph}.
     */
    private class AdjacentVerticesView extends AbstractSet<Integer> {

        /**
         * The set of adjacent vertices to a vertex.  This set is itself a view
         * to the data and is updated by the {@link EdgeList} for a vertex.
         */
        private final Set<Integer> adjacent;
       
        /**
         * Constructs a view around the set of adjacent vertices
         */
        public AdjacentVerticesView(Set<Integer> adjacent) {
            this.adjacent = adjacent;
        }

        /**
         * Throws an {@link UnsupportedOperationException} if called.
         */
        @Override public boolean add(Integer vertex) {
            throw new UnsupportedOperationException("cannot create edges "
                + "using an adjacenct vertices set; use add() instead");
        }

        @Override public boolean contains(Object o) {
            return o instanceof Integer
                && adjacent.contains((Integer)o);
        }

        @Override public boolean isEmpty() {
            return adjacent.isEmpty();
        }

        public Iterator<Integer> iterator() {
            return new AdjacentVerticesIterator();
        }

        @Override public boolean remove(Object o) {
            throw new UnsupportedOperationException("cannot remove edges "
                + "using an adjacenct vertices set; use remove() instead");
        }

        public int size() {
            return adjacent.size();
        }

        /**
         * A decorator around the iterator for an adjacency list's vertices that tracks
         * vertex removal to update the number of edges in the graph.
         */
        private class AdjacentVerticesIterator implements Iterator<Integer> {

            private final Iterator<Integer> vertices;

            public AdjacentVerticesIterator() {
                vertices = adjacent.iterator();
            }

            public boolean hasNext() {
                return vertices.hasNext();
            }

            public Integer next() {
                return vertices.next();
            }

            public void remove() {
                throw new UnsupportedOperationException("cannot remove an edge "
                    + "to an adjacenct vertices using this iterator; use "
                    + "remove() instead");
            }           
        }
    }

    /**
     * A view class that exposes the {@link Edge} information in this graph as a
     * {@link Set}.
     */
    private class EdgeView extends AbstractSet<T> {
       
        public EdgeView() { }

        public boolean add(T e) {
            return AbstractGraph.this.add(e);
        }

        public boolean contains(Object o) {
            return (o instanceof Edge) && AbstractGraph.this.contains((Edge)o);
        }

        public Iterator<T> iterator() {
            return new EdgeViewIterator();
        }

        public boolean remove(Object o) {
            return (o instanceof Edge) && AbstractGraph.this.remove((Edge)o);
        }

        public int size() {
            return numEdges;
        }

        /**
         * A wrapper iterator around all the graph's {@link EdgeSet} iterators.
         * We use this class instead of a {@link
         * edu.ucla.sspace.util.CombinedIterator} in order to construct this
         * edge iterator on the fly (i.e., only one {@code Iterator} is held in
         * memory at a time), which offers some memory savings for graphs with a
         * large number of vertices or where the {@code EdgeSet} iterators have
         * a larger memory overhead.
         *
         * <p> This iterator also tracks successful iterator removals to update
         * the number of edges in this graph.
         */
        private class EdgeViewIterator implements Iterator<T> {

            /**
             * An iterator over the {@link EdgeSet} instances for each of the
             * vertices
             */
            private final Iterator<S> vertices;
           
            /**
             * The iterator from which the next element will be returned
             */
            private Iterator<T> edges;
                                               
            /**
             * The iterator from which the last element was returned.  Any call
             * to remove() will use this iterator
             */
            private Iterator<T> toRemoveFrom;

            private T next;

            private T cur;
           
            private int curRoot = -1;
           
            public EdgeViewIterator() {
                vertices = vertexToEdges.valueCollection().iterator();
                advance();
            }
           
            /**
             * Updates the state of the iterator so that {@code edges} is set to
             * an {@code Iterator} with an element to return, if such an
             * iterator exists.
             */
            private void advance() {
                next = null;
                if ((edges == null || !edges.hasNext()) && !vertices.hasNext())
                    return;
                do {
                    // Find an edge iterator with at least one edge
                    while ((edges == null || !edges.hasNext())
                           && vertices.hasNext()) {
                        S edgeSet = vertices.next();
                        curRoot = edgeSet.getRoot();
                        edges = edgeSet.iterator();
                    }
                    // If we didn't find one, short circuit
                    if (edges == null || !edges.hasNext())
                        return;                  
                    // Get the next edge to examine
                    T e = edges.next();

                    // The backing graph stores symmetric edges in order to
                    // maintain the adjacency lists.  To account for this,
                    // we toss out edges that will have their symmetric
                    // version counted, using the edge's to and from to make
                    // the distinction.
                    if ((curRoot == e.from() && curRoot < e.to())
                            || (curRoot == e.to() && curRoot < e.from()))
                        next = e;
                } while (next == null);
            }
           
            public boolean hasNext() {
                return next != null;
            }

            public T next() {
                if (!hasNext())
                    throw new NoSuchElementException();
                cur = next;
                // Once we've returned an element from the set of edges, the
                // next call to remove() should remove from the current iterator
                if (toRemoveFrom != edges)
                    toRemoveFrom = edges;
                advance();
                return cur;
            }
           
            public void remove() {
                if (cur == null)
                    throw new IllegalStateException("no element to remove");
                AbstractGraph.this.remove(cur);
                cur = null;
            }
        }
    }

    /**
     * A {@link Graph} implementation for representing the view of a subset of a
     * graph's vertices while tracking changes to the graph on which this {@code
     * Subgraph} is a view.
     *
     * <p> All edge information is stored in the backing graph.  {@code
     * Subgraph} instances only retain information on which vertices are
     * currently represented as a part of the subgraph.  Changes to edge by
     * other subgraphs or to the backing graph are automatically detected and
     * incorporated at call time.
     */
    protected class Subgraph implements Graph<T> {
       
        private final IntSet vertexSubset;

        /**
         * Creates a new subgraph from the provided set of vertices
         */
        public Subgraph(Set<Integer> vertices) {
            vertexSubset = new TroveIntSet(vertices);
        }
       
        /**
         * {@inheritDoc}
         */
        public boolean add(int v) {
            if (vertexSubset.contains(v))
                return false;
            throw new UnsupportedOperationException(
                "Cannot add a vertext to a subgraph");
        }
   
        /**
         * {@inheritDoc}
         */
        public boolean add(T e) {
            return vertexSubset.contains(e.from())
                && vertexSubset.contains(e.to())
                && AbstractGraph.this.add(e);
        }

        /**
         * {@inheritDoc}
         */
        public void clear() {
            for (IntIterator it = vertexSubset.iterator(); it.hasNext(); ) {
                int v = it.nextInt();
                AbstractGraph.this.remove(v);
            }
            vertexSubset.clear();
        }
       
        /**
         * {@inheritDoc}
         */
        public void clearEdges() {
            for (T e : edges())
                AbstractGraph.this.remove(e);
        }
   
        /**
         * {@inheritDoc}
         */
        public boolean contains(int vertex1, int vertex2) {
            return vertexSubset.contains(vertex1)
                && vertexSubset.contains(vertex2)
                && AbstractGraph.this.contains(vertex1, vertex2);
        }

        /**
         * {@inheritDoc}
         */
        public boolean contains(Edge e) {
            return vertexSubset.contains(e.from())
                && vertexSubset.contains(e.to())
                && AbstractGraph.this.contains(e);
        }

        /**
         * {@inheritDoc}
         */
        public boolean contains(int v) {
            return vertexSubset.contains(v)
                && AbstractGraph.this.contains(v);
        }

        public Graph<T> copy(Set<Integer> vertices) {
            Graph<T> g =
                AbstractGraph.this.copy(Collections.<Integer>emptySet());
            for (int v : vertices) {
                if (!contains(v))
                    throw new IllegalArgumentException(
                        "Requested copy with non-existant vertex: " + v);
                g.add(v);
                for (T e : getAdjacencyList(v))
                    if (vertices.contains(e.from())
                            && vertices.contains(e.to()))
                        g.add(e);
            }
            return g;
        }

        /**
         * {@inheritDoc}
         */
        public int degree(int vertex) {
            int d = 0;
            for (int n : AbstractGraph.this.getNeighbors(vertex))
                if (vertexSubset.contains(n))
                    d++;
            return d;
        }

        /**
         * {@inheritDoc}
         */
        public Set<T> edges() {
            return new SubgraphEdgeView();
        }

        /**
         * {@inheritDoc}
         */
        @Override public boolean equals(Object o) {
            if (o instanceof Graph) {
                Graph<?> g = (Graph<?>)o;
                return g.order() == order()
                    && g.size() == size()
                    && g.vertices().equals(vertices())
                    && g.edges().equals(edges());                   
            }
            return false;
        }
       
        /**
         * {@inheritDoc}
         */
        public Set<T> getAdjacencyList(int vertex) {
            Set<T> adjList = AbstractGraph.this.getAdjacencyList(vertex);
            return (adjList.isEmpty())
                ? adjList
                : new SubgraphAdjacencyListView(vertex);
        }
       
        /**
         * {@inheritDoc}
         */
        public IntSet getNeighbors(int vertex) {
            return (!vertexSubset.contains(vertex))
                ? PrimitiveCollections.emptyIntSet()
                : new SubgraphNeighborsView(vertex);
                /*
             // REMINDER: make this a view, rather than a created set
             IntSet neighbors = new TroveIntSet();
             IntIterator it =
                 AbstractGraph.this.getNeighbors(vertex).iterator();
             while (it.hasNext()) {
                 int v = it.nextInt();
                 if (vertexSubset.contains(v))
                     neighbors.add(v);
             }
             return neighbors;
                */
        }
       
        /**
         * {@inheritDoc}
         */
        public Set<T> getEdges(int vertex1, int vertex2) {
            return (vertexSubset.contains(vertex1)
                    && vertexSubset.contains(vertex2))
                ? AbstractGraph.this.getEdges(vertex1, vertex2)
                : Collections.<T>emptySet();
        }
       
        /**
         * {@inheritDoc}
         */
        public boolean hasCycles() {
            throw new UnsupportedOperationException("fix me");
        }

        /**
         * {@inheritDoc}
         */
        public int hashCode() {
            return vertices().hashCode();
        }
       
        /**
         * {@inheritDoc}
         */
        public Iterator<Integer> iterator() {
            return vertices().iterator();
        }
        /**
         * {@inheritDoc}
         */
        public int order() {
            return vertexSubset.size();
        }
       
        /**
         * {@inheritDoc}
         */
        public boolean remove(Edge e) {
            return vertexSubset.contains(e.from())
                && vertexSubset.contains(e.to())
                && AbstractGraph.this.remove(e);
        }

        /**
         * {@inheritDoc}
         */
        public boolean remove(int vertex) {
            return vertexSubset.contains(vertex)
                && AbstractGraph.this.remove(vertex);
        }

        /**
         * {@inheritDoc}
         */
        public int size() {
            // Because this is only a view of the backing graph, we can't keep
            // view-local state of the number of edges.  Therefore, we have to
            // calculate how many edges are present on the fly.
            int numEdges = 0;
            for (IntIterator it = vertexSubset.iterator(); it.hasNext(); ) {
                int v = it.nextInt();
                EdgeSet<T> edges = AbstractGraph.this.getEdgeSet(v);
                for (IntIterator it2 = vertexSubset.iterator();
                         it2.hasNext(); ) {
                    int v2 = it2.nextInt();
                    if (v == v2)
                        break;
                    if (edges.connects(v2))
                        numEdges++;
                }
            }
            return numEdges;
        }
           
        /**
         * {@inheritDoc}
         */
        public Graph<T> subgraph(Set<Integer> vertices) {
            if (!vertexSubset.containsAll(vertices))
                throw new IllegalArgumentException("provided set is not a " +
                    "subset of the vertices of this graph");
            return AbstractGraph.this.subgraph(vertices);
        }
       
        public String toString() {
            return "{ vertices: " + vertices() + ", edges: " + edges() + "}";
        }

        /**
         * {@inheritDoc}
         */
        public IntSet vertices() {
            return PrimitiveCollections.unmodifiableSet(vertexSubset);
        }   

        /**
         * A view for the {@code Edge} adjacent edges of a vertex within a
         * subgraph.  This class monitors for changes to edge set to update the
         * state of this graph
         */
        private class SubgraphAdjacencyListView extends AbstractSet<T> {

            private final int root;

            public SubgraphAdjacencyListView(int root) {
                this.root = root;
            }

            public boolean add(T edge) {
                return (edge.from() == root
                        || edge.to() == root)
                    && Subgraph.this.add(edge);
            }

            public boolean contains(Object o) {
                if (!(o instanceof Edge))
                    return false;
                Edge e = (Edge)o;
                return (e.to() == root ||
                         e.from() == root)
                        && Subgraph.this.contains(e);
            }
           
            public Iterator<T> iterator() {
                return new SubgraphAdjacencyListIterator();
            }
           
            public boolean remove(Object o) {
                if (!(o instanceof Edge))
                    return false;
                Edge e = (Edge)o;
                return (e.to() == root ||
                        e.from() == root)
                    && Subgraph.this.remove(e);
            }

            public int size() {               
                int sz = 0;
                for (IntIterator it = vertexSubset.iterator(); it.hasNext(); ) {
                    int v = it.nextInt();
                    if (v == root)
                        continue;
                    Set<T> edges = AbstractGraph.this.getEdges(v, root);
                    sz += edges.size();
                }
                return sz;
            }

            /**
             * A decorator around the iterator for the adjacency list for a
             * vertex in a subgraph, which tracks edges removal to update the
             * number of edges in the graph.
             */
            private class SubgraphAdjacencyListIterator
                    implements Iterator<T> {

                private final Iterator<T> edges;

                public SubgraphAdjacencyListIterator() {
                    List<Iterator<T>> iters = new LinkedList<Iterator<T>>();

                    for (IntIterator it = vertexSubset.iterator();
                             it.hasNext(); ) {
                        int v = it.nextInt();                       
                        if (v == root)
                            continue;
                        Set<T> edges = AbstractGraph.this.getEdges(v, root);
                        if (!edges.isEmpty())
                            iters.add(edges.iterator());
                    }
                    edges = new CombinedIterator<T>(iters);
                }

                public boolean hasNext() {
                    return edges.hasNext();
                }

                public T next() {
                    return edges.next();
                }

                public void remove() {
                    throw new UnsupportedOperationException();
                }
            }
        }

        /**
         * A view-based class over the edges in a {@link Subgraph}.  This class
         * masks the state of the edges that are in the backing graph but not in
         * the subgraph.
         */
        private class SubgraphEdgeView extends AbstractSet<T> {          

            public SubgraphEdgeView() { }

            public boolean add(T e) {
                return Subgraph.this.add(e);
            }

            public boolean contains(T o) {
                return Subgraph.this.contains(o);
            }

            public Iterator<T> iterator() {
                return new SubgraphEdgeIterator();
            }

            public boolean remove(Object o) {
                return (o instanceof Edge)
                    && Subgraph.this.remove((Edge)o);
            }

            public int size() {
                return Subgraph.this.size();
            }

            /**
             *
             */
            private class SubgraphEdgeIterator implements Iterator<T> {

                private final Queue<T> edgesToReturn;

                private final Queue<Integer> remainingVertices;

                private Iterator<Integer> possibleNeighbors;

                private Integer curVertex;

                public SubgraphEdgeIterator() {
                    remainingVertices = new ArrayDeque<Integer>(vertexSubset);
                    edgesToReturn = new ArrayDeque<T>();
                    curVertex = null;
                    advance();
                }
               
                private void advance() {
                    // If there are still edges from the current pair, skip
                    // processing any further connections
                    if (!edgesToReturn.isEmpty())
                        return;
                   
                    do {
                        // Find the next vertex to analyze for connections
                        while ((possibleNeighbors == null
                                    || !possibleNeighbors.hasNext())
                               && !remainingVertices.isEmpty()) {
                            // Pull off the next vertex and then use the remaining
                            // vertices to check for connections
                            curVertex = remainingVertices.poll();
                            possibleNeighbors = remainingVertices.iterator();
                        }
                       
                        // Iterate through the possible neighbors of this
                        // vertex, stopping when we find another vertex that has
                        // at least one edge
                        while (edgesToReturn.isEmpty()
                                   && possibleNeighbors.hasNext()) {
                            Integer v = possibleNeighbors.next();
                            edgesToReturn.addAll(getEdges(curVertex, v));
                        }
                    } while (edgesToReturn.isEmpty()
                             && !remainingVertices.isEmpty());
                }

                public boolean hasNext() {
                    return edgesToReturn.size() > 0;
                }

                public T next() {
                    if (!hasNext())
                        throw new NoSuchElementException();
                    T n = edgesToReturn.poll();
                    advance();
                    return n;
                }

                public void remove() {
                    throw new IllegalStateException();
                }
            }
        }



        /**
         * A view of a subgraph's vertex's neighbors that are also in the
         * subview.  This view monitors for additions and removals to the set in
         * order to update the state of this {@code Subgraph}.
         */
        private class SubgraphNeighborsView extends AbstractIntSet {

            private int root;
           
            /**
             * Constructs a view around the set of adjacent vertices
             */
            public SubgraphNeighborsView(int root) {
                this.root = root;
            }

            public boolean add(int vertex) {
                throw new UnsupportedOperationException(
                    "Cannot add vertices to subgraph");
            }
           
            public boolean add(Integer vertex) {
                throw new UnsupportedOperationException(
                    "Cannot add vertices to subgraph");
            }

            public boolean contains(int vertex) {
                return vertexSubset.contains(vertex) && checkVertex(vertex);
            }
           
            public boolean contains(Object o) {
                if (!(o instanceof Integer))
                    return false;
                Integer i = (Integer)o;
                return vertexSubset.contains(i) && checkVertex(i);
            }

            /**
             * Returns {@code true} if the vertex is connected to the root
             */
            private boolean checkVertex(int i) {
                return AbstractGraph.this.contains(i, root);
            }

            public IntIterator iterator() {
                return new SubgraphNeighborsIterator();
            }
           
            public boolean remove(int vertex) {
                throw new UnsupportedOperationException(
                    "Cannot remove vertices from subgraph");
            }
           
            public boolean remove(Object vertex) {
                throw new UnsupportedOperationException(
                    "Cannot remove vertices from subgraph");
            }
           
            public int size() {
                int sz = 0;
                for (IntIterator it = vertexSubset.iterator();
                         it.hasNext(); ) {
                    int v = it.nextInt();
                    if (checkVertex(v))
                        sz++;
                }
                return sz;
            }

            /**
             * A decorator around the iterator for a subgraphs's neighboring
             * vertices set, which keeps track of which neighboring vertices are
             * actually in this subview.
             */
            private class SubgraphNeighborsIterator implements IntIterator {

                private final IntIterator iter;

                private Integer next;

                public SubgraphNeighborsIterator() {
                    iter = vertexSubset.iterator();
                    advance();
                }
               
                /**
                 * Finds the next adjacent vertex that is also in this subview.
                 */
                private void advance() {
                    next = null;
                    while (iter.hasNext() && next == null) {
                        int v = iter.next();
                        if (checkVertex(v))
                            next = v;
                    }                   
                }

                public boolean hasNext() {
                    return next != null;
                }

                public Integer next() {
                    if (!hasNext())
                        throw new NoSuchElementException();
                    Integer cur = next;
                    advance();
                    return cur;
                }

                public int nextInt() {
                    return next();
                }

                /**
                 * Throws an {@link UnsupportedOperationException} if called.
                 */
                public void remove() {
                    throw new UnsupportedOperationException();
                }           
            }
        }
    }
}
TOP

Related Classes of edu.ucla.sspace.graph.Subgraph$SubgraphNeighborsView$SubgraphNeighborsIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.