Search code examples
graphguava

Simple example of Guava ValueGraph


I'm looking for simple example of Guava ValueGraph. Something like:

class GraphNode {
  String name;
  String value;
  // Do I need to override equals & hashcode methods here??

}

class GraphUser {
  public ValueGraph<GraphNode,Double> createGraph(){
    ValueGraph<GraphNode,Double> graph = ValueGraphBuilder.directed.build();
    // How do I add the nodes to graph??
    // How do I add the edges to graph?
  }
}
  1. How do I create graph with custom object as node?
  2. How do I add nodes & edges to graph?
  3. Do I have to override the equals & hashCode methods in the custom node class?

A simple example would be very helpful.


Solution

  • The Guava wiki gives the following example for using ValueGraph:

    MutableValueGraph<Integer, Double> weightedGraph = ValueGraphBuilder.directed().build();
    weightedGraph.addNode(1);
    weightedGraph.putEdgeValue(2, 3, 1.5);  // also adds nodes 2 and 3 if not already present
    weightedGraph.putEdgeValue(3, 5, 1.5);  // edge values (like Map values) need not be unique
    ...
    weightedGraph.putEdgeValue(2, 3, 2.0);  // updates the value for (2,3) to 2.0
    

    I'll do my best to answer your other questions in the order which you asked them:

    1. How do I create graph with custom object as node?

      public final class GraphNode {
        private final String name;
        private final int age;
      
        GraphNode(String name, int age) {
          this.name = Objects.requireNonNull(name, "name");
          this.age = age;
        }
      
        public String name() {
          return name;
        }
      
        public int age() {
          return age;
        }
      
        @Override
        public boolean equals(Object other) {
          if (other instanceof GraphNode) {
            GraphNode that = (GraphNode) other;
            return this.name.equals(that.name)
                && this.age == that.age;
          }
          return false;
        }
      
        @Override
        public int hashCode() {
          return Objects.hash(name, age);
        }
      
        @Override
        public String toString() {
          return "(" + name + ", " + age + ")";
        }
      }
      

    More on creating a value graph with objects of this class later.

    1. How do I add nodes & edges to graph?

      MutableValueGraph<GraphNode, Double> weightedGraph = ValueGraphBuilder.directed().build();
      GraphNode a = new GraphNode("Jonathan", 20);
      GraphNode b = new GraphNode("Nicolas", 40);
      GraphNode c = new GraphNode("Georgia", 30);
      weightedGraph.putEdgeValue(a, b, 2.0);
      weightedGraph.putEdgeValue(a, c, 4.5);
      

      This will produce a graph like the following (arrows going down):

             (Jonathan, 20)
                   / \
                2.0   4.5
                 /     \
      (Nicolas, 40)   (Georgia, 30)
      
    2. Do I have to override the equals & hashCode methods in the custom node class?

      It's not strictly necessary, but it's highly encouraged, because otherwise, with the following code example, the graph will likely look different to what you'd expect it to be.

      MutableValueGraph<GraphNode, Double> weightedGraph = ValueGraphBuilder.directed().build();
      GraphNode a = new GraphNode("Jonathan", 20);
      GraphNode b = new GraphNode("Nicolas", 40);
      GraphNode c = new GraphNode("Georgia", 30);
      weightedGraph.putEdgeValue(a, b, 2.0);
      weightedGraph.putEdgeValue(a, c, 4.5);
      weightedGraph.putEdgeValue(b, new GraphNode("Luke", 10), 6.0);
      weightedGraph.putEdgeValue(c, new GraphNode("Luke", 10), 1.5);
      

      With custom equals() and hashCode() implementations in GraphNode, the graph will produce the following expected shape:

              (Jonathan, 20)
                   / \
                2.0   4.5
                 /     \
      (Nicolas, 40)   (Georgia, 30)
                 \     /
                6.0   1.5
                   \ /
               (Luke, 10)
      

      But without equals() and hashCode(), the value graph will be unable to tell that the two new GraphNode("Luke", 10)s are logically the same node, and so it will produce the following erroneous shape:

              (Jonathan, 20)
                   / \
                2.0   4.5
                 /     \
      (Nicolas, 40)   (Georgia, 30)
                |       |
               6.0     1.5
                |       |
         (Luke, 10)   (Luke, 10)
      

    I hope this helps!