public void union(AbstractBaseGraph<V, E> g2) { if (!(this instanceof DirectedGraph<?, ?> && g2 instanceof DirectedGraph<?, ?>)) { return; } Set<V> vertexSet = g2.vertexSet(); for (V vertex : vertexSet) { if (!containsVertex(vertex)) addVertex(vertex); } for (V vertex : vertexSet) { Set<E> edgeSet = g2.specifics.outgoingEdgesOf(vertex); for (E edge : edgeSet) { V sourceVertex = getEdgeSource(edge); V targetVertex = getEdgeTarget(edge); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { continue; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { continue; } if (containsEdge(edge)) { continue; } else { IntrusiveEdge intrusiveEdge = createIntrusiveEdge(edge, sourceVertex, targetVertex); edgeMap.put(edge, intrusiveEdge); specifics.addEdgeToTouchingVertices(edge); } } } }
/** @see Graph#addEdge(Object, Object, Object) */ public boolean addEdge(V sourceVertex, V targetVertex, E e) { if (e == null) { throw new NullPointerException(); } else if (containsEdge(e)) { return false; } assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { return false; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } IntrusiveEdge intrusiveEdge = createIntrusiveEdge(e, sourceVertex, targetVertex); edgeMap.put(e, intrusiveEdge); specifics.addEdgeToTouchingVertices(e); return true; }
/** @see Graph#edgeSet() */ public Set<E> edgeSet() { if (unmodifiableEdgeSet == null) { unmodifiableEdgeSet = Collections.unmodifiableSet(edgeMap.keySet()); } return unmodifiableEdgeSet; }
/** @see Graph#addEdge(Object, Object) */ public E addEdge(V sourceVertex, V targetVertex) { assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { return null; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } E e = edgeFactory.createEdge(sourceVertex, targetVertex); if (containsEdge(e)) { // this restriction should stay! return null; } else { IntrusiveEdge intrusiveEdge = createIntrusiveEdge(e, sourceVertex, targetVertex); edgeMap.put(e, intrusiveEdge); specifics.addEdgeToTouchingVertices(e); return e; } }
private void markPath(V v, V child, V stem, Set<V> blossom) { while (!contracted.get(v).equals(stem)) { blossom.add(contracted.get(v)); blossom.add(contracted.get(match.get(v))); path.put(v, child); child = match.get(v); v = path.get(match.get(v)); } }
/** @see Graph#removeEdge(Object) */ public boolean removeEdge(E e) { if (containsEdge(e)) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); return true; } else { return false; } }
/** @see Graph#removeEdge(Object, Object) */ public E removeEdge(V sourceVertex, V targetVertex) { E e = getEdge(sourceVertex, targetVertex); if (e != null) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); } return e; }
private V lowestCommonAncestor(V a, V b) { Set<V> seen = new HashSet<>(); for (; ; ) { a = contracted.get(a); seen.add(a); if (!match.containsKey(a)) { break; } a = path.get(match.get(a)); } for (; ; ) { b = contracted.get(b); if (seen.contains(b)) { return b; } b = path.get(match.get(b)); } }
/** * Runs the algorithm on the input graph and returns the match edge set. * * @return set of Edges */ private Set<E> findMatch() { Set<E> result = new ArrayUnenforcedSet<>(); match = new HashMap<>(); path = new HashMap<>(); contracted = new HashMap<>(); for (V i : graph.vertexSet()) { // Any augmenting path should start with _exposed_ vertex // (vertex may not escape match-set being added once) if (!match.containsKey(i)) { // Match is maximal iff graph G contains no more augmenting paths V v = findPath(i); while (v != null) { V pv = path.get(v); V ppv = match.get(pv); match.put(v, pv); match.put(pv, v); v = ppv; } } } Set<V> seen = new HashSet<>(); graph .vertexSet() .stream() .filter(v -> !seen.contains(v) && match.containsKey(v)) .forEach( v -> { seen.add(v); seen.add(match.get(v)); result.add(graph.getEdge(v, match.get(v))); }); return result; }
/** @see Graph#containsEdge(Object) */ public boolean containsEdge(E e) { return edgeMap.containsKey(e); }
private IntrusiveEdge getIntrusiveEdge(E e) { if (e instanceof IntrusiveEdge) { return (IntrusiveEdge) e; } return edgeMap.get(e); }
private V findPath(V root) { Set<V> used = new HashSet<>(); Queue<V> q = new ArrayDeque<>(); // Expand graph back from its contracted state path.clear(); contracted.clear(); graph.vertexSet().forEach(vertex -> contracted.put(vertex, vertex)); used.add(root); q.add(root); while (!q.isEmpty()) { V v = q.remove(); for (E e : graph.edgesOf(v)) { V to = graph.getEdgeSource(e); if (to.equals(v)) { to = graph.getEdgeTarget(e); } if ((contracted.get(v).equals(contracted.get(to))) || to.equals(match.get(v))) { continue; } // Check whether we've hit a 'blossom' if ((to.equals(root)) || ((match.containsKey(to)) && (path.containsKey(match.get(to))))) { V stem = lowestCommonAncestor(v, to); Set<V> blossom = new HashSet<>(); markPath(v, to, stem, blossom); markPath(to, v, stem, blossom); graph .vertexSet() .stream() .filter(i -> contracted.containsKey(i) && blossom.contains(contracted.get(i))) .forEach( i -> { contracted.put(i, stem); if (!used.contains(i)) { used.add(i); q.add(i); } }); // Check whether we've had hit a loop (of even length (!) presumably) } else if (!path.containsKey(to)) { path.put(to, v); if (!match.containsKey(to)) { return to; } to = match.get(to); used.add(to); q.add(to); } } } return null; }