private boolean edgesCompatible(int edge1, int edge2) { E e1 = edgeList1.get(edge1); E e2 = edgeList2.get(edge2); boolean result = false; // edge label must be the same if (e1.getLabel().equals(e2.getLabel())) { // check connecting vertex labels L v1SourceLbl = g1.getEdgeSource(e1).getLabel(), v1TargetLbl = g1.getEdgeTarget(e1).getLabel(), v2SourceLbl = g2.getEdgeSource(e2).getLabel(), v2TargetLbl = g2.getEdgeTarget(e2).getLabel(); // checks if the pair of source vertices have the same label, and checks the same for the // target vertices boolean sourceTargetMatch = v1SourceLbl.equals(v2SourceLbl) && v1TargetLbl.equals(v2TargetLbl); if (directed) { result = sourceTargetMatch; } else { // checks if source1,target2 have the same label and if target1,source2 have the same label boolean sourceTargetInverseMatch = v1SourceLbl.equals(v2TargetLbl) && v1TargetLbl.equals(v2SourceLbl); result = (sourceTargetMatch || sourceTargetInverseMatch); } } return result; }
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); } } }
/** * @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; }
@Override public TraversalGraph<V, E> reconstructTraversalGraph() { if (currentStartNode == null) { throw new IllegalStateException( "You must call #calculate before " + "reconstructing the traversal graph."); } TraversalGraph<V, E> traversalGraph = new TraversalGraph<V, E>(graph.getEdgeFactory(), currentStartNode); for (V v : graph.vertexSet()) { Set<E> predEdges = (Set<E>) v.getPredecessorEdges(); for (E e : predEdges) { V source = graph.getEdgeSource(e); V target = graph.getEdgeTarget(e); traversalGraph.addVertex(source); traversalGraph.addVertex(target); if (v.equals(source)) { traversalGraph.addEdge(target, source).setBaseGraphEdge(e); } else if (v.equals(target)) { traversalGraph.addEdge(source, target).setBaseGraphEdge(e); } else { throw new IllegalStateException( "A vertex has a predecessor " + "edge not ending on itself."); } } } return traversalGraph; }
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; }
/** * @return the amount of arcs that are connected on both sides to nodes that have been mapped so * far */ public int getArcsLeftForMappedVertices() { int result = 0; boolean columnOr; for (int y = 0; y < dimy; y++) { columnOr = false; for (int x = 0; x < dimx; x++) { columnOr |= matrix[x][y]; } if (columnOr) { // if Edge edgeList2.get(y) is connected (on both sides) to vertices in mappedVerticesFromG2 if (mappedVerticesFromG2.contains(g2.getEdgeSource(edgeList2.get(y))) && mappedVerticesFromG2.contains(g2.getEdgeSource(edgeList2.get(y)))) { result++; } } } return result; }
/** * Compute all vertices that have positive degree by iterating over the edges on purpose. This * keeps the complexity to O(m) where m is the number of edges. * * @param graph the graph * @return set of vertices with positive degree */ private Set<V> initVisibleVertices(Graph<V, E> graph) { Set<V> visibleVertex = new HashSet<>(); for (E e : graph.edgeSet()) { V s = graph.getEdgeSource(e); V t = graph.getEdgeTarget(e); if (!s.equals(t)) { visibleVertex.add(s); visibleVertex.add(t); } } return visibleVertex; }
/** Calculates the matrix of all shortest paths, but does not populate the paths map. */ private void lazyCalculateMatrix() { if (d != null) { // already done return; } int n = vertices.size(); // init the backtrace matrix backtrace = new int[n][n]; for (int i = 0; i < n; i++) { Arrays.fill(backtrace[i], -1); } // initialize matrix, 0 d = new double[n][n]; for (int i = 0; i < n; i++) { Arrays.fill(d[i], Double.POSITIVE_INFINITY); } // initialize matrix, 1 for (int i = 0; i < n; i++) { d[i][i] = 0.0; } // initialize matrix, 2 Set<E> edges = graph.edgeSet(); for (E edge : edges) { V v1 = graph.getEdgeSource(edge); V v2 = graph.getEdgeTarget(edge); int v_1 = vertices.indexOf(v1); int v_2 = vertices.indexOf(v2); d[v_1][v_2] = graph.getEdgeWeight(edge); if (!(graph instanceof DirectedGraph<?, ?>)) { d[v_2][v_1] = graph.getEdgeWeight(edge); } } // run fw alg for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { double ik_kj = d[i][k] + d[k][j]; if (ik_kj < d[i][j]) { d[i][j] = ik_kj; backtrace[i][j] = k; } } } } }
public long countExternalEdges(Integer i, Set<DefaultWeightedEdge> neighborSet) { int numberExternalEdges = 0; // count number of external edges for (DefaultWeightedEdge edge : neighborSet) { // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh! Integer src = graph.getEdgeSource(edge); Integer dst = graph.getEdgeTarget(edge); Integer other = src.equals(i) ? dst : src; if (contains(other)) { numberExternalEdges -= 1; } else { numberExternalEdges += 1; } } return numberExternalEdges; }
V getEdgeSource(E e) { return graph.getEdgeSource(e); }
// the algorithm (improved with additional heuristics) private Pair<Double, Set<E>> runWithHeuristics(Graph<V, E> graph) { // lookup all relevant vertices Set<V> visibleVertex = initVisibleVertices(graph); // create solver for paths DynamicProgrammingPathSolver pathSolver = new DynamicProgrammingPathSolver(); Set<E> matching = new HashSet<>(); double matchingWeight = 0d; Set<V> matchedVertices = new HashSet<>(); // run algorithm while (!visibleVertex.isEmpty()) { // find vertex arbitrarily V x = visibleVertex.stream().findAny().get(); // grow path from x LinkedList<E> path = new LinkedList<>(); while (x != null) { // first heaviest edge incident to vertex x (among visible neighbors) double maxWeight = 0d; E maxWeightedEdge = null; V maxWeightedNeighbor = null; for (E e : graph.edgesOf(x)) { V other = Graphs.getOppositeVertex(graph, e, x); if (visibleVertex.contains(other) && !other.equals(x)) { double curWeight = graph.getEdgeWeight(e); if (comparator.compare(curWeight, 0d) > 0 && (maxWeightedEdge == null || comparator.compare(curWeight, maxWeight) > 0)) { maxWeight = curWeight; maxWeightedEdge = e; maxWeightedNeighbor = other; } } } // add edge to path and remove x if (maxWeightedEdge != null) { path.add(maxWeightedEdge); } visibleVertex.remove(x); // go to next vertex x = maxWeightedNeighbor; } // find maximum weight matching of path using dynamic programming Pair<Double, Set<E>> pathMatching = pathSolver.getMaximumWeightMatching(graph, path); // add it to result while keeping track of matched vertices matchingWeight += pathMatching.getFirst(); for (E e : pathMatching.getSecond()) { V s = graph.getEdgeSource(e); V t = graph.getEdgeTarget(e); if (!matchedVertices.add(s)) { throw new RuntimeException("Set is not a valid matching, please submit a bug report"); } if (!matchedVertices.add(t)) { throw new RuntimeException("Set is not a valid matching, please submit a bug report"); } matching.add(e); } } // extend matching to maximal cardinality (out of edges with positive weight) for (E e : graph.edgeSet()) { double edgeWeight = graph.getEdgeWeight(e); if (comparator.compare(edgeWeight, 0d) <= 0) { // ignore zero or negative weight continue; } V s = graph.getEdgeSource(e); if (matchedVertices.contains(s)) { // matched vertex, ignore continue; } V t = graph.getEdgeTarget(e); if (matchedVertices.contains(t)) { // matched vertex, ignore continue; } // add edge to matching matching.add(e); matchingWeight += edgeWeight; } // return extended matching return Pair.of(matchingWeight, matching); }
/** * @param connectedOnly if true, the result will be a connected graph * @return */ public Graph<V, E> toGraph() { if (subgraph != null) return subgraph; if (directed) { subgraph = new DirectedMultigraph<V, E>(g2.getEdgeFactory()); } else { subgraph = new Multigraph<V, E>(g2.getEdgeFactory()); } E edge; V source; V target; for (int x = 0; x < dimx; x++) { for (int y = 0; y < dimy; y++) { if (matrix[x][y]) { edge = edgeList2.get(y); source = g2.getEdgeSource(edge); target = g2.getEdgeTarget(edge); if (mappedVerticesFromG2.contains(source) && mappedVerticesFromG2.contains(target)) { // make sure the source and target vertices have been added, then add the edge subgraph.addVertex(source); subgraph.addVertex(target); subgraph.addEdge(source, target, edge); } } } } if (connectedOnly) { // make sure this subgraph is connected, if it is not return the largest connected part List<Set<V>> connectedVertices = new ArrayList<Set<V>>(); for (V v : subgraph.vertexSet()) { if (!SharedStaticMethods.containsV(connectedVertices, v)) { connectedVertices.add(SharedStaticMethods.getConnectedVertices(subgraph, v)); } } // ConnectedVertices now contains Sets of connected vertices every vertex of the subgraph is // contained exactly once in the list // if there is more then 1 set, then this method should return the largest connected part of // the graph if (connectedVertices.size() > 1) { Graph<V, E> largestResult = null; Graph<V, E> currentGraph; int largestSize = -1; Set<V> currentSet; for (int i = 0; i < connectedVertices.size(); i++) { currentSet = connectedVertices.get(i); /*note that 'subgraph' is the result from the Mcgregor algorithm, 'currentGraph' is an * induced subgraph of 'subgraph'. 'currentGraph' is connected, because the vertices in * 'currentSet' are connected with edges in 'subgraph' */ currentGraph = new Subgraph<V, E, Graph<V, E>>(subgraph, currentSet); if (currentGraph.edgeSet().size() > largestSize) { largestResult = currentGraph; } } return largestResult; } } return subgraph; }