javajgrapht

Algorithm to compress my Graph (JGraphT) by delete certain edges and vertexes


I have a graph that i want to compress by creating a new graph. So the vertexes are "Topological Nodes" and the edges are different objects but they have the same parent class. Now in the example i want to delete all edges with type b.

The vertices "Topological Nodes" have a Number (1,2,3). Nothing more so very simple. The edges have a reference to these nodes.

Example:

  Graph {
    //uncompressed Graph
    1 -- 2 [label="a1"];
    2 -- 3 [label="b1"];
    3 -- 4 [label="b2"];
    4 -- 5 [label="b3"];
    5 -- 1 [label="a2"];
  }

uncompressed

Graph {
    //compressed Graph
    5 -- 1 [label="a2"];
    5 -- 1 [label="a1"];
}

compressed

What i have so far is this:

public void compression(Graph<TopologicalNode, IdentifiedObject> unCompressedGraph){


    Set<SubGeographicalRegion> networks = datamodel.equipmentProfile.keySet();
    for (SubGeographicalRegion subGeographicalRegion : networks) {
        Graph<TopologicalNode, IdentifiedObject> compressedGraph = GraphTypeBuilder
                .<TopologicalNode, IdentifiedObject>undirected().allowingSelfLoops(true)
                .edgeClass(IdentifiedObject.class).buildGraph();

        ArrayList<PowerTransformer> powerTransformers = getPTsFromSubnet(subGeographicalRegion);

        for(PowerTransformer powerTransformer :powerTransformers) {
            for (PowerTransformerEnd powerTransformerEnd : powerTransformer.getEnds()) {
                if (unCompressedGraph.vertexSet().stream().filter(r -> r.equals(powerTransformerEnd.getTerminal().getTopologicalNode())).findAny().isPresent()) {
                    TopologicalNode start = unCompressedGraph.vertexSet().stream().filter(r -> r.equals(powerTransformerEnd.getTerminal().getTopologicalNode())).findAny().get();
                    compressedGraph.addVertex(start);
                    ArrayList<TopologicalNode> nodesToBeCompressed = new ArrayList<>();
                    Iterator<TopologicalNode> iterator = new DepthFirstIterator<>(unCompressedGraph, start);
                    while (iterator.hasNext()) {
                        TopologicalNode nextNode = iterator.next();
                     
                        Set<IdentifiedObject> eqs = unCompressedGraph.edgesOf(nextNode);
                        //TODO: How to go on?
                    }
                }
            }
        }
    }
}

So i dont really know how to go on and i am new to JGraphT.


Solution

  • It seems you intend to delete an edge by removing it and merging the nodes touched by the edges. You could do this by:

    1. Finding the edge e1 and its both endpoints, say u and v, in the graph.

    2a. If there are multiple edges between u an v, then just remove the edge and there's nothing else to do.

    2b. If there's only one edge between u and v, we proceed as follows. Create a new vertex w. Vertex w will be the new 'merged' node. Remove edge e1. Connect all edges from u to its neighbors to w. Do the same for v. Remove nodes u and v.

    In code, this translates to:

    public static void main(String[] args){
        //Create a graph
        Graph<Integer, String> g =
                new Pseudograph<>(SupplierUtil.createIntegerSupplier(1), null, false);
        for(int i=0; i<5; i++)
            g.addVertex();
        g.addEdge(1,2,"a1");
        g.addEdge(2,3,"b1");
        g.addEdge(3,4,"b2");
        g.addEdge(4,5,"b3");
        g.addEdge(5,1,"a2");
    
        removeEdge(g,"b1");
        removeEdge(g,"b2");
        removeEdge(g,"b3");
        System.out.println(g);
    }
    private static void removeEdge(Graph<Integer, String> g, String edge){
        if(!g.containsEdge(edge))
            throw new RuntimeException(String.format("Cannot delete edge %s because this edge does not exist in the graph!", edge));
    
        Integer u=g.getEdgeSource(edge);
        Integer v=g.getEdgeTarget(edge);
    
        //Case 2a: there are multiple edges between vertex u and v
        if(g.getAllEdges(u,v).size()>1){
            g.removeEdge(edge);
            return;
        }
        //Case 2b: there is only 1 edge between u and v. Delete the edge, and merge nodes u and v into new node w.
        g.removeEdge(edge);
        Integer w=g.addVertex();
        Set<String> edgesOfU = new HashSet<>(g.edgesOf(u));
        Set<String> edgesOfV = new HashSet<>(g.edgesOf(v));
        //Remove all edges between u and its neighbors and re-add those edges for node w
        for(String e : edgesOfU){
            Integer neighbor = Graphs.getOppositeVertex(g,e,u);
            g.removeEdge(e);
            g.addEdge(w,neighbor,e);
        }
        //Remove all edges between v and its neighbors and re-add those edges for node w
        for(String e : edgesOfV){
            Integer neighbor = Graphs.getOppositeVertex(g,e,v);
            g.removeEdge(e);
            g.addEdge(w,neighbor,e);
        }
        //Nodes u and v have been replaced by w, so we can safely remove u and v
        g.removeVertex(u);
        g.removeVertex(v);
    }
    

    When executing this code we get the desired graph:

    ([1, 8], [a1={8,1}, a2={8,1}])
    

    Note that, the delete-and-merge operation could produce graphs with multiple edges between the same node, or self-loops, so we need to use a Pseudograph as underlying graph type.