/** * Create a copy of a graph for internal use. * * @param graph the graph to copy. * @return A copy of the graph projected to a SimpleGraph. */ private static <V, E> UndirectedGraph<V, E> copyAsSimpleGraph(UndirectedGraph<V, E> graph) { UndirectedGraph<V, E> copy = new SimpleGraph<>(graph.getEdgeFactory()); if (graph instanceof SimpleGraph) { Graphs.addGraph(copy, graph); } else { // project graph to SimpleGraph Graphs.addAllVertices(copy, graph.vertexSet()); for (E e : graph.edgeSet()) { V v1 = graph.getEdgeSource(e); V v2 = graph.getEdgeTarget(e); if ((v1 != v2) && !copy.containsEdge(e)) { copy.addEdge(v1, v2); } } } return copy; }
/** * 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())); } }
private SimpleGraph<Integer, DefaultEdge> buildGraphForTestDisconnected(int size) { SimpleGraph<Integer, DefaultEdge> graph = new SimpleGraph<>(DefaultEdge.class); VertexFactory<Integer> vertexFactory = new IntegerVertexFactory(); CompleteGraphGenerator<Integer, DefaultEdge> completeGraphGenerator = new CompleteGraphGenerator<>(size); // two complete graphs SimpleGraph<Integer, DefaultEdge> east = new SimpleGraph<>(DefaultEdge.class); completeGraphGenerator.generateGraph(east, vertexFactory, null); SimpleGraph<Integer, DefaultEdge> west = new SimpleGraph<>(DefaultEdge.class); completeGraphGenerator.generateGraph(west, vertexFactory, null); Graphs.addGraph(graph, east); Graphs.addGraph(graph, west); // connected by single edge graph.addEdge(size - 1, size); return graph; }
protected Graph<String, DefaultWeightedEdge> createWithBias(boolean negate) { Graph<String, DefaultWeightedEdge> g; double bias = 1; if (negate) { // negative-weight edges are being tested, so only a directed graph // makes sense g = new SimpleDirectedWeightedGraph<String, DefaultWeightedEdge>(DefaultWeightedEdge.class); bias = -1; } else { // by default, use an undirected graph g = new SimpleWeightedGraph<String, DefaultWeightedEdge>(DefaultWeightedEdge.class); } g.addVertex(V1); g.addVertex(V2); g.addVertex(V3); g.addVertex(V4); g.addVertex(V5); e12 = Graphs.addEdge(g, V1, V2, bias * 2); e13 = Graphs.addEdge(g, V1, V3, bias * 3); e24 = Graphs.addEdge(g, V2, V4, bias * 5); e34 = Graphs.addEdge(g, V3, V4, bias * 20); e45 = Graphs.addEdge(g, V4, V5, bias * 5); e15 = Graphs.addEdge(g, V1, V5, bias * 100); return g; }
/** * 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); } }