private void init(Graph<V, E> g, Set<V> vertexSet, Set<E> edgeSet) { // create a map between vertex value to its order(1st,2nd,etc) // "CAT"=1 "DOG"=2 "RHINO"=3 this.mapVertexToOrder = new HashMap<V, Integer>(vertexSet.size()); int counter = 0; for (V vertex : vertexSet) { mapVertexToOrder.put(vertex, new Integer(counter)); counter++; } // create a friendlier representation of an edge // by order, like 2nd->3rd instead of B->A // use the map to convert vertex to order // on directed graph, edge A->B must be (A,B) // on undirected graph, edge A-B can be (A,B) or (B,A) this.labelsEdgesSet = new HashSet<LabelsEdge>(edgeSet.size()); for (E edge : edgeSet) { V sourceVertex = g.getEdgeSource(edge); Integer sourceOrder = mapVertexToOrder.get(sourceVertex); int sourceLabel = sourceOrder.intValue(); int targetLabel = (mapVertexToOrder.get(g.getEdgeTarget(edge))).intValue(); LabelsEdge lablesEdge = new LabelsEdge(sourceLabel, targetLabel); this.labelsEdgesSet.add(lablesEdge); if (g instanceof UndirectedGraph<?, ?>) { LabelsEdge oppositeEdge = new LabelsEdge(targetLabel, sourceLabel); this.labelsEdgesSet.add(oppositeEdge); } } }
/** @see Graph#getEdgeWeight */ @Override public double getEdgeWeight(E e) { double weight; // Always return the value from the weight map first and // only pass the call through as a backup if (weightMap.containsKey(e)) { weight = weightMap.get(e); } else { weight = super.getEdgeWeight(e); } return weight; }
/** * @param graph the graph to be ordered * @param orderByDegree should the vertices be ordered by their degree. This speeds up the VF2 * algorithm. * @param cacheEdges if true, the class creates a adjacency matrix and two arrays for incoming and * outgoing edges for fast access. */ public GraphOrdering(Graph<V, E> graph, boolean orderByDegree, boolean cacheEdges) { this.graph = graph; this.cacheEdges = cacheEdges; List<V> vertexSet = new ArrayList<>(graph.vertexSet()); if (orderByDegree) { java.util.Collections.sort(vertexSet, new GeneralVertexDegreeComparator<>(graph)); } vertexCount = vertexSet.size(); mapVertexToOrder = new HashMap<>(); mapOrderToVertex = new ArrayList<>(vertexCount); if (cacheEdges) { outgoingEdges = new int[vertexCount][]; incomingEdges = new int[vertexCount][]; adjMatrix = new Boolean[vertexCount][vertexCount]; } Integer i = 0; for (V vertex : vertexSet) { mapVertexToOrder.put(vertex, i++); mapOrderToVertex.add(vertex); } }
/** @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; } }
/** @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; }
/** * @param vertexNumber the number which identifies the vertex v in this order. * @return the identifying numbers of all vertices which are connected to v by an edge incoming to * v. */ public int[] getInEdges(int vertexNumber) { if (cacheEdges && (incomingEdges[vertexNumber] != null)) { return incomingEdges[vertexNumber]; } V v = getVertex(vertexNumber); Set<E> edgeSet; if (graph instanceof DirectedGraph<?, ?>) { edgeSet = ((DirectedGraph<V, E>) graph).incomingEdgesOf(v); } else { edgeSet = graph.edgesOf(v); } int[] vertexArray = new int[edgeSet.size()]; int i = 0; for (E edge : edgeSet) { V source = graph.getEdgeSource(edge), target = graph.getEdgeTarget(edge); vertexArray[i++] = mapVertexToOrder.get(source.equals(v) ? target : source); } if (cacheEdges) { incomingEdges[vertexNumber] = vertexArray; } return vertexArray; }
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); } } } }
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)); } }
public int[] getEdgeNumbers(E e) { V v1 = graph.getEdgeSource(e), v2 = graph.getEdgeTarget(e); int[] edge = new int[2]; edge[0] = mapVertexToOrder.get(v1); edge[1] = mapVertexToOrder.get(v2); return edge; }
/** @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; }
/** @see Graph#removeEdge(Object) */ public boolean removeEdge(E e) { if (containsEdge(e)) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); return true; } else { return false; } }
/** @see WeightedGraph#setEdgeWeight */ @Override public void setEdgeWeight(E e, double weight) { if (isWeightedGraph) { super.setEdgeWeight(e, weight); } // Always modify the weight map. It would be a terrible violation // of the use contract to silently ignore changes to the weights. weightMap.put(e, weight); }
/** * Get the vertex with the maximal label. * * @param vertexLabels Map that gives a label for each vertex. * @return Vertex with the maximal label. */ private V getMaxLabelVertex(Map<V, Integer> vertexLabels) { Iterator<Entry<V, Integer>> iterator = vertexLabels.entrySet().iterator(); Entry<V, Integer> max = iterator.next(); while (iterator.hasNext()) { Entry<V, Integer> e = iterator.next(); if (e.getValue() > max.getValue()) { max = e; } } return max.getKey(); }
/** {@inheritDoc} */ public void generateGraph( Graph<V, E> target, VertexFactory<V> vertexFactory, Map<String, V> resultMap) { V lastVertex = null; for (int i = 0; i < size; ++i) { V newVertex = vertexFactory.createVertex(); target.addVertex(newVertex); if (lastVertex == null) { if (resultMap != null) { resultMap.put(START_VERTEX, newVertex); } } else { target.addEdge(lastVertex, newVertex); } lastVertex = newVertex; } if ((resultMap != null) && (lastVertex != null)) { resultMap.put(END_VERTEX, lastVertex); } }
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)); } }
/** {@inheritDoc} */ public void generateGraph( Graph<V, E> target, final VertexFactory<V> vertexFactory, Map<String, V> resultMap) { if (size < 1) { return; } // A little trickery to intercept the rim generation. This is // necessary since target may be initially non-empty, meaning we can't // rely on its vertex set after the rim is generated. final Collection<V> rim = new ArrayList<V>(); VertexFactory<V> rimVertexFactory = new VertexFactory<V>() { public V createVertex() { V vertex = vertexFactory.createVertex(); rim.add(vertex); return vertex; } }; RingGraphGenerator<V, E> ringGenerator = new RingGraphGenerator<V, E>(size - 1); ringGenerator.generateGraph(target, rimVertexFactory, resultMap); V hubVertex = vertexFactory.createVertex(); target.addVertex(hubVertex); if (resultMap != null) { resultMap.put(HUB_VERTEX, hubVertex); } for (V rimVertex : rim) { if (inwardSpokes) { target.addEdge(rimVertex, hubVertex); } else { target.addEdge(hubVertex, rimVertex); } } }
/** * 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; }
public int getVertexNumber(V v) { return mapVertexToOrder.get(v); }
public void testCornerCases() { DirectedWeightedMultigraph<Integer, DefaultWeightedEdge> simple = new DirectedWeightedMultigraph<>(DefaultWeightedEdge.class); simple.addVertex(0); simple.addVertex(1); DefaultWeightedEdge e = simple.addEdge(0, 1); try { new EdmondsKarpMFImpl<Integer, DefaultWeightedEdge>(null); fail(); } catch (NullPointerException ex) { } try { new EdmondsKarpMFImpl<>(simple, -0.1); fail(); } catch (IllegalArgumentException ex) { } try { simple.setEdgeWeight(e, -1.0); new EdmondsKarpMFImpl<>(simple); fail(); } catch (IllegalArgumentException ex) { } try { simple.setEdgeWeight(e, 1.0); MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> solver = new EdmondsKarpMFImpl<>(simple); Map<DefaultWeightedEdge, Double> flow = solver.buildMaximumFlow(0, 1).getFlow(); flow.put(e, 25.0); fail(); } catch (UnsupportedOperationException ex) { } try { MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> solver = new EdmondsKarpMFImpl<>(simple); solver.buildMaximumFlow(2, 0); fail(); } catch (IllegalArgumentException ex) { } try { MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> solver = new EdmondsKarpMFImpl<>(simple); solver.buildMaximumFlow(1, 2); fail(); } catch (IllegalArgumentException ex) { } try { MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> solver = new EdmondsKarpMFImpl<>(simple); solver.buildMaximumFlow(0, 0); fail(); } catch (IllegalArgumentException ex) { } try { MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> solver = new EdmondsKarpMFImpl<>(simple); solver.buildMaximumFlow(null, 0); fail(); } catch (IllegalArgumentException ex) { } try { MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> solver = new EdmondsKarpMFImpl<>(simple); solver.buildMaximumFlow(0, null); fail(); } catch (IllegalArgumentException ex) { } }
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; }
/** * Compute the minimal triangulation of the graph. Implementation of Algorithm MCS-M+ 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 computeMinimalTriangulation() { // initialize chordGraph with same vertices as graph chordalGraph = new SimpleGraph<>(graph.getEdgeFactory()); for (V v : graph.vertexSet()) { chordalGraph.addVertex(v); } // initialize g' as subgraph of graph (same vertices and edges) final UndirectedGraph<V, E> gprime = copyAsSimpleGraph(graph); int s = -1; generators = new ArrayList<>(); meo = new LinkedList<>(); final Map<V, Integer> vertexLabels = new HashMap<>(); for (V v : gprime.vertexSet()) { vertexLabels.put(v, 0); } for (int i = 1, n = graph.vertexSet().size(); i <= n; i++) { V v = getMaxLabelVertex(vertexLabels); LinkedList<V> Y = new LinkedList<>(Graphs.neighborListOf(gprime, v)); if (vertexLabels.get(v) <= s) { generators.add(v); } s = vertexLabels.get(v); // Mark x reached and all other vertices of gprime unreached HashSet<V> reached = new HashSet<>(); reached.add(v); // mark neighborhood of x reached and add to reach(label(y)) HashMap<Integer, HashSet<V>> reach = new HashMap<>(); // mark y reached and add y to reach for (V y : Y) { reached.add(y); addToReach(vertexLabels.get(y), y, reach); } for (int j = 0; j < graph.vertexSet().size(); j++) { if (!reach.containsKey(j)) { continue; } while (reach.get(j).size() > 0) { // remove a vertex y from reach(j) V y = reach.get(j).iterator().next(); reach.get(j).remove(y); for (V z : Graphs.neighborListOf(gprime, y)) { if (!reached.contains(z)) { reached.add(z); if (vertexLabels.get(z) > j) { Y.add(z); E fillEdge = graph.getEdgeFactory().createEdge(v, z); fillEdges.add(fillEdge); addToReach(vertexLabels.get(z), z, reach); } else { addToReach(j, z, reach); } } } } } for (V y : Y) { chordalGraph.addEdge(v, y); vertexLabels.put(y, vertexLabels.get(y) + 1); } meo.addLast(v); gprime.removeVertex(v); vertexLabels.remove(v); } }
/** @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); }
/** * Access the data stored for a seen vertex. * * @param vertex a vertex which has already been seen. * @return data associated with the seen vertex or <code>null</code> if no data was associated * with the vertex. A <code>null</code> return can also indicate that the vertex was * explicitly associated with <code> * null</code>. */ protected D getSeenData(V vertex) { return seen.get(vertex); }
/** * Determines whether a vertex has been seen yet by this traversal. * * @param vertex vertex in question * @return <tt>true</tt> if vertex has already been seen */ protected boolean isSeenVertex(Object vertex) { return seen.containsKey(vertex); }
/** * Stores iterator-dependent data for a vertex that has been seen. * * @param vertex a vertex which has been seen. * @param data data to be associated with the seen vertex. * @return previous value associated with specified vertex or <code> * null</code> if no data was associated with the vertex. A <code> * null</code> return can also indicate that the vertex was explicitly associated with <code>null * </code>. */ protected D putSeenData(V vertex, D data) { return seen.put(vertex, data); }