Erdos icon indicating copy to clipboard operation
Erdos copied to clipboard

Adding multiple vertices with the same data

Open Carpetfizz opened this issue 7 years ago • 4 comments

Hello,

Let's say I have a Vertex of the following form:

Vertex<MyClass> myVertex = new Vertex<>(myObject.getMessage());

In my program, it is possible for a Vertex with the same data to get graph.addVertex()'d. I want to be able to stop the graph from adding a Vertex if another one with the same data exists. I saw that the Vertex.hashCode is a function of some auto generated ID. If my data source is guaranteed to be unique elements, is it possible to make the hash a function of the data instead of a random ID ?

Thanks for any advice.

Carpetfizz avatar Mar 18 '17 00:03 Carpetfizz

hi @Carpetfizz I may have a solution for you, but first read why we made the Vertex class instances unique. the hash is not exactly random id. It is an auto incremented integer. building in the hashcode of a message is dangerous. It has been thought of back then when the library was designed, basically:

  • even if the vertex's hashcode depends on the message, you will still need to override equals() so that the graph will understand it already has that vertex.
  • when the lib was first designed, on of it's intents was to easily move vertices from one graph to another and even to duplicate graphs(we didn't do it), therefore we wanted every vertex to be unique, so we don't get collisions and we also didn't override the equals() method.
  • we even made hashcode final for that purpose in Vertex

but you still can do it, my suggestion is very simple:

  • graphs receive IVertex in graph.addVertex(..)
  • implement a new IVertex, that uses most of the Vertex implementation, and write your own hashcode and override equals(..)
  • you are welcome to contribute this new vertex afterwards

hope that helps

HendrixString avatar Mar 18 '17 20:03 HendrixString

Thank you so much! I just copied and pasted the Vertex code and overrode the following functions:

@Override
public final int hashCode() {
    return "unique_vertex".hashCode() + getData().hashCode();
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }

    if (obj == null) {
        return false;
    }

    if (getClass() != obj.getClass()) {
        return false;
    }

    UniqueVertex otherUniqueVertex = (UniqueVertex) obj;

    return this.getData().equals(otherUniqueVertex.getData());
}

Now, I'm trying to do the same for DirectedEdge but but the Edge class has the following comment in the header:

directed edges with similar vertices and direction are equal (Java equality).

But I'm not finding this to be the case. The edges in the graph keep increasing as I add more of the same edge. Consider the following toString representation of my graph:

id=null, tag=null::V = {4, 2, 1, 3, } E = {4->2, 2->4, 4->1, 2->1, 4->2, 1->2, 4->3, 2->3, 1->3, }

The Vertex fix has worked thanks to your help, but the DirectedEdge 4->2 appears twice.

My requirement is that the edge should be the same but the edge's data can be different. I'm using the graph to map geometric relationships between vertices, which can change. So, the edge (1, 2, data=x) and (1,2, data=y) should count as the same edge between (1, 2) but the data should get updated.

Any advice on this would be appreciated.

Carpetfizz avatar Mar 19 '17 17:03 Carpetfizz

@Carpetfizz yeah I see. because we wanted to support multi-edges, i.e - multiple edges on the same two vertices, no two edges can be the same, even if they may be isomorphic, so you can have two edges that may seem the same like 4->2. but, it should only appear in graphs that support multi edges. In your case it is a bug, that can be fixed as follows:

override the Vertex.getId() method so it will return the same id for two similar vertices, i.e vertices that have the same data. stringify the hashcode for example. it should work, since, the graph engine adds and detects edges presence by the id of their vertices.

under the hood, it serializes like this:

public static String getEdgeDesc(IVertex v1, IVertex v2, EDGE_DIRECTION edgeType) {
        String res      = null;

        if(edgeType==EDGE_DIRECTION.DIRECTED) {
            res         =  (v1.getId() + "->" + v2.getId());
        }
        else if(edgeType==EDGE_DIRECTION.UNDIRECTED) {
            int compare = v1.getId().compareTo(v2.getId());
            if(compare < 0)
                res     = v1.getId() + "<->" + v2.getId();
            else
                res     = v2.getId() + "<->" + v1.getId();
        }

        return res;
    }

HendrixString avatar Mar 19 '17 19:03 HendrixString

Thanks again for the response, I think I left out another requirement by accident. I do indeed want a directed multigraph, but multiple edges connecting the same two vertices will definitely contain different data. Will your above solution still work in this scenario?

Carpetfizz avatar Mar 20 '17 00:03 Carpetfizz