/** * Returns a List with unique elements, * * @param v1 vertex from g1 * @return */ public List<V> getPrioritySubset(V v1) { // The resulting list List<V> result = new ArrayList<V>(); // list of already mapped vertices that neighbour v1 List<V> v1Others = new ArrayList<V>(); V v1other; V v2other; for (E e1 : g1.edgesOf(v1)) { v1other = Graphs.getOppositeVertex(g1, e1, v1); if (mappedVerticesFromG1.contains(v1other)) { v1Others.add(v1other); } } for (V v2 : g2.vertexSet()) { // if v2's label is the same of v1's label and v2 has not been mapped yet if (v1.getLabel().equals(v2.getLabel()) && !mappedVerticesFromG2.contains(v2)) { // test if there is an edge to a vertex which has already been mapped for (E e2 : g2.edgesOf(v2)) { v2other = Graphs.getOppositeVertex(g2, e2, v2); // if the vertex v2other has already been mapped if (mappedVerticesFromG2.contains(v2other)) { // labels are not checked, this is done at a later stage anyway and doing it twice is // not needed and takes too much time result.add(v2); break; } } } } return result; }
/** * @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 static Set outgoingEdgesOf(Graph g, Object node) { if (g instanceof DirectedGraph) { return ((DirectedGraph) g).outgoingEdgesOf(node); } else { return g.edgesOf(node); } }
@Override public boolean add(Integer i) { // maintain unweighted volume Set<DefaultWeightedEdge> neighborSet = graph.edgesOf(i); volume += neighborSet.size(); // maintain correct denominator to compute conductance with denominator = Math.min(volume, totalVolume - volume); // count how many external edges this node has with the community external_edges += countExternalEdges(i, neighborSet); conductance = external_edges / (double) denominator; return super.add(i); }
@Override public boolean remove(Object o) { Integer i = (Integer) o; // maintain unweighted volume Set<DefaultWeightedEdge> neighborSet = graph.edgesOf(i); volume -= neighborSet.size(); // maintain correct denominator to compute conductance with denominator = Math.min(volume, totalVolume - volume); boolean retValue = super.remove(i); // count how many external edges this node has with the community, and remove them (opposite of // add) external_edges -= countExternalEdges(i, neighborSet); conductance = external_edges / (double) denominator; return retValue; }
/** * Return the change in conductance which would occur from adding a particular vertex to the set. * This is linear in the degree of the vertex. ie., O(degree(toAdd)) */ @Override public double getDeltaConductance(Integer vertex, boolean add) { Set<DefaultWeightedEdge> neighborSet = graph.edgesOf(vertex); int degree_U = neighborSet.size(); long delta_E = 0; delta_E = countExternalEdges(vertex, neighborSet); if (!add) { delta_E = -1 * delta_E; degree_U = -1 * degree_U; } long new_volume = volume + degree_U; long new_denom = Math.min(new_volume, totalVolume - new_volume); double rescaled_conductance = ((denominator) / (double) (new_denom)) * conductance; double final_conductance = rescaled_conductance + (delta_E) / (double) (new_denom); // this is the change in conductance if one were to add node u return final_conductance - conductance; }
Set<E> edgesOf(V vertex) { return graph.edgesOf(vertex); }
// 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); }
// the algorithm (no heuristics) private Pair<Double, Set<E>> run(Graph<V, E> graph) { // lookup all relevant vertices Set<V> visibleVertex = initVisibleVertices(graph); // run algorithm Set<E> m1 = new HashSet<>(); Set<E> m2 = new HashSet<>(); double m1Weight = 0d, m2Weight = 0d; int i = 1; while (!visibleVertex.isEmpty()) { // find vertex arbitrarily V x = visibleVertex.stream().findAny().get(); // grow path from x 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 it to either m1 or m2, alternating between them if (maxWeightedEdge != null) { switch (i) { case 1: m1.add(maxWeightedEdge); m1Weight += maxWeight; break; case 2: m2.add(maxWeightedEdge); m2Weight += maxWeight; break; default: throw new RuntimeException("Failed to figure out matching, seems to be a bug"); } i = 3 - i; } // remove x and incident edges visibleVertex.remove(x); // go to next vertex x = maxWeightedNeighbor; } } // return best matching if (comparator.compare(m1Weight, m2Weight) > 0) { return Pair.of(m1Weight, m1); } else { return Pair.of(m2Weight, m2); } }
@Override public int compare(V2 v1, V2 v2) { return graph.edgesOf(v1).size() - graph.edgesOf(v2).size(); }
/** @see CrossComponentIterator.Specifics#edgesOf(Object) */ public Set<EE> edgesOf(VV vertex) { return graph.edgesOf(vertex); }
/* Each time a node in G1 is tentatively paired with a node in G2, MARCS is refined on the basis of this node correspondence. Say node i in G1 is tentatively paired with node j in G2. Then any arc r connected to node i in G1 can correspond only to arcs which are connected to node j in G2. This is represented in MARCS by setting to zero any bit (r, s) such that arc r is connected to node i in G, and arc s is not connected to node j in G2. */ public void refine(V v1, V v2) { // marcs is modified, make sure subgraph is set to null (to prevent errors) subgraph = null; mappedVerticesFromG1.add(v1); mappedVerticesFromG2.add(v2); List<Integer> edgesV1Ints = null; List<Integer> edgesV2Ints = null; List<Integer> edgesV1OutInts = null; List<Integer> edgesV1InInts = null; List<Integer> edgesV2OutInts = null; List<Integer> edgesV2InInts = null; if (!directed) { edgesV1Ints = new ArrayList<Integer>(); edgesV2Ints = new ArrayList<Integer>(); for (E e1 : g1.edgesOf(v1)) { edgesV1Ints.add(edgeList1.indexOf(e1)); } for (E e2 : g2.edgesOf(v2)) { edgesV2Ints.add(edgeList2.indexOf(e2)); } } else { // directed edgesV1OutInts = new ArrayList<Integer>(); edgesV1InInts = new ArrayList<Integer>(); edgesV2OutInts = new ArrayList<Integer>(); edgesV2InInts = new ArrayList<Integer>(); for (E e1 : ((DirectedGraph<V, E>) g1).outgoingEdgesOf(v1)) { edgesV1OutInts.add(edgeList1.indexOf(e1)); } for (E e1 : ((DirectedGraph<V, E>) g1).incomingEdgesOf(v1)) { edgesV1InInts.add(edgeList1.indexOf(e1)); } for (E e2 : ((DirectedGraph<V, E>) g2).outgoingEdgesOf(v2)) { edgesV2OutInts.add(edgeList2.indexOf(e2)); } for (E e2 : ((DirectedGraph<V, E>) g2).incomingEdgesOf(v2)) { edgesV2InInts.add(edgeList2.indexOf(e2)); } } for (int x = 0; x < dimx; x++) { if (!rowOrs[x]) continue; for (int y = 0; y < dimy; y++) { // if the only one of the two edges x and y are connected to v1 or v2 then x and y are not // compatible and the matrix should be set to false if (matrix[x][y]) { if (directed) { if ((edgesV1OutInts.contains(x) && !edgesV2OutInts.contains(y)) || (!edgesV1OutInts.contains(x) && edgesV2OutInts.contains(y)) || (edgesV1InInts.contains(x) && !edgesV2InInts.contains(y)) || (!edgesV1InInts.contains(x) && edgesV2InInts.contains(y))) { matrix[x][y] = false; } } else { // undirected if ((edgesV1Ints.contains(x) && !edgesV2Ints.contains(y)) || (!edgesV1Ints.contains(x) && edgesV2Ints.contains(y))) { matrix[x][y] = false; } } } } } }