/** @see java.util.Iterator#hasNext() */ public boolean hasNext() { if (startVertex != null) { encounterStartVertex(); } if (isConnectedComponentExhausted()) { if (state == CCS_WITHIN_COMPONENT) { state = CCS_AFTER_COMPONENT; if (nListeners != 0) { fireConnectedComponentFinished(ccFinishedEvent); } } if (isCrossComponentTraversal()) { while (vertexIterator.hasNext()) { V v = vertexIterator.next(); if (!isSeenVertex(v)) { encounterVertex(v, null); state = CCS_BEFORE_COMPONENT; return true; } } return false; } else { return false; } } else { return true; } }
/** @see Graph#getAllEdges(Object, Object) */ public Set<E> getAllEdges(V sourceVertex, V targetVertex) { Set<E> edges = null; if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { edges = new ArrayUnenforcedSet<E>(); Iterator<E> iter = getEdgeContainer(sourceVertex).vertexEdges.iterator(); while (iter.hasNext()) { E e = iter.next(); boolean equalStraight = sourceVertex.equals(getEdgeSource(e)) && targetVertex.equals(getEdgeTarget(e)); boolean equalInverted = sourceVertex.equals(getEdgeTarget(e)) && targetVertex.equals(getEdgeSource(e)); if (equalStraight || equalInverted) { edges.add(e); } } } return edges; }
/** * Creates a new iterator for the specified graph. Iteration will start at the specified start * vertex. If the specified start vertex is <code> * null</code>, Iteration will start at an arbitrary graph vertex. * * @param g the graph to be iterated. * @param startVertex the vertex iteration to be started. * @throws IllegalArgumentException if <code>g==null</code> or does not contain <code>startVertex * </code> */ public CrossComponentIterator(Graph<V, E> g, V startVertex) { super(); if (g == null) { throw new IllegalArgumentException("graph must not be null"); } graph = g; specifics = createGraphSpecifics(g); vertexIterator = g.vertexSet().iterator(); setCrossComponentTraversal(startVertex == null); reusableEdgeEvent = new FlyweightEdgeEvent<V, E>(this, null); reusableVertexEvent = new FlyweightVertexEvent<V>(this, null); if (startVertex == null) { // pick a start vertex if graph not empty if (vertexIterator.hasNext()) { this.startVertex = vertexIterator.next(); } else { this.startVertex = null; } } else if (g.containsVertex(startVertex)) { this.startVertex = startVertex; } else { throw new IllegalArgumentException("graph must contain the start vertex"); } }
/** * Compute the unique decomposition of the input graph G (atoms of G). Implementation of algorithm * Atoms as described in Berry et al. (2010), DOI:10.3390/a3020197, <a * href="http://www.mdpi.com/1999-4893/3/2/197">http://www.mdpi.com/1999-4893/3/2/197</a> */ private void computeAtoms() { if (chordalGraph == null) { computeMinimalTriangulation(); } separators = new HashSet<>(); // initialize g' as subgraph of graph (same vertices and edges) UndirectedGraph<V, E> gprime = copyAsSimpleGraph(graph); // initialize h' as subgraph of chordalGraph (same vertices and edges) UndirectedGraph<V, E> hprime = copyAsSimpleGraph(chordalGraph); atoms = new HashSet<>(); Iterator<V> iterator = meo.descendingIterator(); while (iterator.hasNext()) { V v = iterator.next(); if (generators.contains(v)) { Set<V> separator = new HashSet<>(Graphs.neighborListOf(hprime, v)); if (isClique(graph, separator)) { if (separator.size() > 0) { if (separators.contains(separator)) { fullComponentCount.put(separator, fullComponentCount.get(separator) + 1); } else { fullComponentCount.put(separator, 2); separators.add(separator); } } UndirectedGraph<V, E> tmpGraph = copyAsSimpleGraph(gprime); tmpGraph.removeAllVertices(separator); ConnectivityInspector<V, E> con = new ConnectivityInspector<>(tmpGraph); if (con.isGraphConnected()) { throw new RuntimeException("separator did not separate the graph"); } for (Set<V> component : con.connectedSets()) { if (component.contains(v)) { gprime.removeAllVertices(component); component.addAll(separator); atoms.add(new HashSet<>(component)); assert (component.size() > 0); break; } } } } hprime.removeVertex(v); } if (gprime.vertexSet().size() > 0) { atoms.add(new HashSet<>(gprime.vertexSet())); } }
/** @see Graph#getEdge(Object, Object) */ public E getEdge(V sourceVertex, V targetVertex) { if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { DirectedEdgeContainer<V, E> ec = getEdgeContainer(sourceVertex); Iterator<E> iter = ec.outgoing.iterator(); while (iter.hasNext()) { E e = iter.next(); if (getEdgeTarget(e).equals(targetVertex)) { return e; } } } return null; }
/** * This method will check whether the graph passed in is Eulerian or not. * * @param g The graph to be checked * @return true for Eulerian and false for non-Eulerian */ public static <V, E> boolean isEulerian(UndirectedGraph<V, E> g) { // If the graph is not connected, then no Eulerian circuit exists if (!(new ConnectivityInspector<V, E>(g)).isGraphConnected()) { return false; } // A graph is Eulerian if and only if all vertices have even degree // So, this code will check for that Iterator<V> iter = g.vertexSet().iterator(); while (iter.hasNext()) { V v = iter.next(); if ((g.degreeOf(v) % 2) == 1) { return false; } } return true; }
/** @see Graph#getEdge(Object, Object) */ public E getEdge(V sourceVertex, V targetVertex) { if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { Iterator<E> iter = getEdgeContainer(sourceVertex).vertexEdges.iterator(); while (iter.hasNext()) { E e = iter.next(); boolean equalStraight = sourceVertex.equals(getEdgeSource(e)) && targetVertex.equals(getEdgeTarget(e)); boolean equalInverted = sourceVertex.equals(getEdgeTarget(e)) && targetVertex.equals(getEdgeSource(e)); if (equalStraight || equalInverted) { return e; } } } return null; }
/** @see Graph#getAllEdges(Object, Object) */ public Set<E> getAllEdges(V sourceVertex, V targetVertex) { Set<E> edges = null; if (containsVertex(sourceVertex) && containsVertex(targetVertex)) { edges = new ArrayUnenforcedSet<E>(); DirectedEdgeContainer<V, E> ec = getEdgeContainer(sourceVertex); Iterator<E> iter = ec.outgoing.iterator(); while (iter.hasNext()) { E e = iter.next(); if (getEdgeTarget(e).equals(targetVertex)) { edges.add(e); } } } return edges; }
/** * Updates outgoing vertices of the vertex. For each outgoing vertex, the new paths are obtained * by concatenating the specified edge to the calculated paths of the specified vertex. If the * weight of a new path is greater than the weight of any path stored so far at the outgoing * vertex then the path is not added, otherwise it is added to the list of paths in increasing * order of weight. Complexity = * * <ul> * <li>O(<code>d(v)*k*(m+n)</code>) where <code>d(v)</code> is the outgoing degree of the * specified vertex, <code>k</code> is the maximum number of shortest paths to compute, * <code>m</code> is the number of edges of the graph and <code>n</code> is the number of * vertices of the graph * </ul> * * @param vertex * @param improvedVertices */ private void updateOutgoingVertices(V vertex, Set<V> improvedVertices) { // try to add new paths for the target vertices of the outgoing edges // of the vertex in argument. for (Iterator<E> iter = edgesOfIterator(vertex); iter.hasNext(); ) { E edge = iter.next(); V vertexReachedByEdge = Graphs.getOppositeVertex(this.graph, edge, vertex); // check if the path does not loop over the start vertex. if (!vertexReachedByEdge.equals(this.startVertex)) { if (this.seenDataContainer.containsKey(vertexReachedByEdge)) { boolean relaxed = tryToAddNewPaths(vertexReachedByEdge, edge); if (relaxed) { improvedVertices.add(vertexReachedByEdge); } } else { boolean relaxed = tryToAddFirstPaths(vertexReachedByEdge, edge); if (relaxed) { improvedVertices.add(vertexReachedByEdge); } } } } }
/** {@inheritDoc} */ public void generateGraph( Graph<V, E> target, VertexFactory<V> vertexFactory, Map<String, V> resultMap) { if (size < 1) { return; } // Add all the vertices to the set for (int i = 0; i < size; i++) { V newVertex = vertexFactory.createVertex(); target.addVertex(newVertex); } /* * We want two iterators over the vertex set, one fast and one slow. * The slow one will move through the set once. For each vertex, * the fast iterator moves through the set, adding an edge to all * vertices we haven't connected to yet. * * If we have an undirected graph, the second addEdge call will return * nothing; it will not add a second edge. */ Iterator<V> slowI = target.vertexSet().iterator(); Iterator<V> fastI; while (slowI.hasNext()) { // While there are more vertices in the set V latestVertex = slowI.next(); fastI = target.vertexSet().iterator(); // Jump to the first vertex *past* latestVertex while (fastI.next() != latestVertex) {; } // And, add edges to all remaining vertices V temp; while (fastI.hasNext()) { temp = fastI.next(); target.addEdge(latestVertex, temp); target.addEdge(temp, latestVertex); } } }
/** * This method will return a list of vertices which represents the Eulerian circuit of the graph. * * @param g The graph to find an Eulerian circuit * @return null if no Eulerian circuit exists, or a list of vertices representing the Eulerian * circuit if one does exist */ public static <V, E> List<V> getEulerianCircuitVertices(UndirectedGraph<V, E> g) { // If the graph is not Eulerian then just return a null since no // Eulerian circuit exists if (!isEulerian(g)) { return null; } // The circuit will be represented by a linked list List<V> path = new LinkedList<V>(); UndirectedGraph<V, E> sg = new UndirectedSubgraph<V, E>(g, null, null); path.add(sg.vertexSet().iterator().next()); // Algorithm for finding an Eulerian circuit Basically this will find an // arbitrary circuit, then it will find another arbitrary circuit until // every edge has been traversed while (sg.edgeSet().size() > 0) { V v = null; // Find a vertex which has an edge that hasn't been traversed yet, // and keep its index position in the circuit list int index = 0; for (Iterator<V> iter = path.iterator(); iter.hasNext(); index++) { v = iter.next(); if (sg.degreeOf(v) > 0) { break; } } // Finds an arbitrary circuit of the current vertex and // appends this into the circuit list while (sg.degreeOf(v) > 0) { for (Iterator<V> iter = sg.vertexSet().iterator(); iter.hasNext(); ) { V temp = iter.next(); if (sg.containsEdge(v, temp)) { path.add(index, temp); sg.removeEdge(v, temp); v = temp; break; } } } } return path; }