Review called by John Reekie and Michael Shilman for the Diva Graph package. Eager to stabilize API as soon as possible.
http://ptolemy.eecs.berkeley.edu/~johnr/diva/api/diva/graph/package-summary.html
diva.graph.Edge
diva.graph.EdgeSet
diva.graph.Graph
diva.graph.GraphEvent
diva.graph.GraphListener
diva.graph.GraphModel
diva.graph.Node
diva.graph.SubGraphModel
diva.graph.CompoundNode
http://ptolemy.eecs.berkeley.edu/~johnr/diva/api/diva/util/package-summary.html
diva.util.PropertyIndexSet
diva.util.PropertyContainer
Review started:1.30 PM
Review ended: 3.00 PM
This design review was extremely useful to me. I didn't agree with all the points that were raised, but the general message that I took away from the meeting was that the facade pattern of the GraphModel class was not completely understood, and this was due to ambiguity in the fact that Nodes/Edges/Graphs were given a full and self-consistent interface. It occurred to me that if it all topology-editing operations were done through the GraphModel interface and that the only low-level operations were "read" operations and "userObject/property" calls, then nearly all of the problems and ambiguities brought up in the design review would be fixed. I am writing a new version of the overview document which will discuss this in more detail.
Overview Document
Fixed.
Fixed.
Shortened and integrated into overview section.
Redesigned. In the new design, low-level "write" operations are only possible through the GraphModel interface. For efficiency it is possible to turn off notifications on the GraphModel. However, when the notifications are turned back on after an algorithm has completed, it will dispatch a STRUCTURE_CHANGED event to cause clients to refresh their views.
Though this graph package is general, its primary goal is as a data structure for a graph visualization system. Because decisions made at this level must be supported by visualization front-ends, it is easier to make the graph interface as minimal as possible, and since hyper-edges can be simulated using specially-tagged nodes, this is probably the easiest for front-ends to deal with.
Neither. I was going to implement directedness and other "common properties" as properties, and store their property names in some globally-available place so that all graph algorithms could share them. However, this is almost the same thing as making them fundamental. So my compromise is to define another set of interfaces RawEdge/RawNode/RawGraph which implement the "raw" graph containment and connectivity, and then make Edge/Node/Graph extend these and extend PropertyContainer/UserObjectContainer and add these "almost fundamental" properties of nodes and edges.
Preliminary benchmarks show a 1-4x performance improvement over Hashtable using an assortment of graph sizes and numbers of properties. It also occurred to me that PropertyIndexSet has an implicit "garbage collection" which Hashtables lack. See the documentation for more details. I believe that this optimization is justified; applications are slow enough as it is.
Benchmarks should show the improvement over hashtables. If this is the case, then there is no better way that I can think of.
Edge
No longer a consideration under the new interface design.
No longer a consideration under the new interface design, but fixed in the actual underlying implementation.
Fixed.
It has been decided that the graph package will not support concurrency. It is up to the user to provide concurrency support. This is a common practice in the recent Java code.
No longer a consideration under the new interface design.
No longer a consideration under the new interface design. The interfaces for graphs/nodes/edges are now read-only.
No longer a consideration under the new interface design.
No. The low- and high-level APIs are more distinct in the new interface design, and in fact it is now encouraged to always use the high-level APIs in all common package usage..
No longer relevant in new interface design.
No longer a consideration under the new interface design.
EdgeSet
No longer relevant in new interface design.
No longer relevant in new interface design.
Greatly improved in new interface design. GraphModel implements a tight policy.
getParent() removed..
getParent() removed..
No longer visible to the user in the new API.
Don't understand...
GraphModel implementations can provide graph-checking routines, since it knows the underlying structure of the graph.
Graph
Under consideration...
Don't understand...
Don't understand...
Fixed.
Fixed.
In a typical graph package there is no need for edges that cut across arbitrary graphs so it is easier to create a symmetry between edges and nodes. However, in this graph package "containment" and "connectivity" are more or less orthogonal, with nodes as the common point. So because an edge doesn't "belong" to a graph per se, I don't think that a symmetry is possible, nor am I convinced that it's particularly useful.
Node
No longer visible to the user in the new API.
GraphModel
Fixed.
Added extra addNode() method that does this.
There is no longer a SubModel interface. GraphModel now contains a method getRoot() that returns the root model. Implementations can choose how this is implemented. In BasicGraphModel, there are two constructors, one for the top-most model and one for a sub-model; that's all the user needs to know.
GraphSubModel has been removed. Now GraphModel knows about hierarchy. The root GraphModel has a null root reference.
Fixed.
I have chosen the following set of events: { edge_head_changed, edge_tail_changed, edge_data_changed, node_added, node_deleted, node_data_changed, structure_changed }. Though the edge_head_changed and edge_tail_changed might allow listeners to get into strange states, they are the minimal events necessary to implement a listener that can mirror the original graph. It is assumed that the end-user code that generated these events will either be through a "safe" API (a la GraphModel) or that it will be written with care. It is also not out of the question to write listeners which are careful about the events they receive.
Alternately, I could have "edge_added" and "edge_deleted" methods, but this might initiate more work than is necessary on any particular
Should be in GraphModel. If it's in Graph, it's too fine-grained and algorithms cannot leverage the hash-once efficiency.
Don't understand.
Fixed. getRoot() now returns a pointer to the root GraphModel. getGraph() returns the model's graph.
Don't understand.
Fixed.
Fixed.
No, and it doesn't make sense either. The UserObject semantics has been moved to a separate interface, where it explains in detail the semantics of the user object and why this doesn't make sense. Use the property mechanism for annotating the node with algorithm annotation..
none
There were more reviewers than customary because a number of people were new to design reviews. (In general, three to five reviewers is optimum.) This is the first review with significant participation by both the Newton and Lee research groups! It was great. One of the Ptolemy reviewers said that he was surprised and pleased at the different perspective he got from the reviewers from the Newton group. -- johnr
Comments to:
michaels@eecs.berkeley.edu