4

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.

jbduncan
  • 425
  • 9
  • 17
RV.
  • 2,781
  • 3
  • 29
  • 46

1 Answers1

11

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!

jbduncan
  • 425
  • 9
  • 17
  • Great example! Any idea how to persist it to DB? – Serafins Dec 19 '19 at 14:19
  • @Serafins The answer at https://stackoverflow.com/a/43712301/2252930 has an idea for this (specifically, using a graph file format - avoid the Java serialization idea if at all possible because Java serialization has security problems as described in Effective Java). But if you're stuck after reading it, then feel free to create a new question with the tag [guava]; I keep an eye on that tag, so I'd be able to find your question, and I'll answer it the best I can. :) – jbduncan Dec 20 '19 at 00:04
  • @jbduncan is there a way I can print the graph in the format you've shown above? – Arun Gowda Mar 27 '21 at 12:34
  • @ArunGowda There isn't, AFAIK. The closest you can get is to find a library or [write some code](https://stackoverflow.com/a/61038828/2252930) to turn a Guava graph into a GraphViz .dot file - or alternatively use JGraphT's [Guava wrapper library](https://jgrapht.org/guide/UserOverview#guava-graph-adapter) and [GraphViz output library](https://jgrapht.org/guide/UserOverview#graph-serialization-and-exportimport) together - and then use GraphViz to [create an image](https://graphviz.org/doc/info/output.html) from the .dot file. I hope this helps. – jbduncan Mar 28 '21 at 12:43
  • I guess I was not clear. I want to print the graph structure in the console for debugging purpose :). like you've shown above. – Arun Gowda Mar 29 '21 at 02:19
  • Oh, I see! I actually crafted the tree above by hand, so AFAIK there's no library out there that prints graphs as text like that. However, `Graph` itself has a `toString()` that prints the nodes and edges of the graph on a single line, which is okay for small graphs but not for large ones. Try it out anyway, but if your graph is too big, you'll need to use my GraphViz suggestion instead. – jbduncan Mar 30 '21 at 09:56
  • If you're still stuck, please raise a new question here on StackOverflow so that other people can find it more easily. :) – jbduncan Mar 30 '21 at 09:59