| 1 | After working on some documentation for the library (porting to quickbook), I have been rethinking many of the requirements of these new classes. Although this design |
| 2 | is not radically different than that of [wiki:soc/2007/UserFriendlyGraphDesignTwo my second iteration], it somewhat more refined, targeting a very specific set of |
| 3 | criteria: specifically, usability. The basic outline follows: |
| 4 | |
| 5 | {{{ |
| 6 | #!cpp |
| 7 | namespace boost { |
| 8 | template <class VP, class EP, class GP> |
| 9 | class undirected_graph |
| 10 | { |
| 11 | typedef adjacency_list<vecS, vecS, undirectedS, VP, EP, GP, listS> graph_type; |
| 12 | graph_type g; |
| 13 | |
| 14 | public: |
| 15 | // ... |
| 16 | |
| 17 | inline graph_type& impl() |
| 18 | { return g; } |
| 19 | |
| 20 | inline const graph_type& impl() const |
| 21 | { return g; } |
| 22 | }; |
| 23 | |
| 24 | // the add_edge method... |
| 25 | template <class VP, class EP, class GP> |
| 26 | inline std::pair<undirected_graph<VP,EP,GP>::edge_descriptor, bool> |
| 27 | add_edge(undirected_graph<VP,EP,GP> &g |
| 28 | undirected_graph<VP,EP,GP>::vertex_descriptor u, |
| 29 | undirected_graph<VP,EP,GP>::vertex_desrciptor v) |
| 30 | { |
| 31 | return boost::add_edge(g.impl(), u, v); |
| 32 | } |
| 33 | } |
| 34 | }}} |
| 35 | |
| 36 | Note that an alterntative to exposing an `impl()` method would be to have the class host all of common operations as member variables and have free functions call those. This would completely hide the underlying `adjacency_list` from the user. For example, |
| 37 | |
| 38 | {{{ |
| 39 | #!cpp |
| 40 | namespace boost { |
| 41 | template <class VP, class EP, class GP> |
| 42 | class undirected_graph |
| 43 | { |
| 44 | typedef adjacency_list<vecS, vecS, undirectedS, VP, EP, GP, listS> graph_type; |
| 45 | graph_type g; |
| 46 | |
| 47 | public: |
| 48 | // ... |
| 49 | |
| 50 | inline std::pair<edge_descriptor, bool> |
| 51 | add_edge(vertex_descriptor u, vertex_descriptor v) |
| 52 | { return boost::add_edge(u, v, g); |
| 53 | }; |
| 54 | |
| 55 | // the add_edge method... |
| 56 | template <class VP, class EP, class GP> |
| 57 | inline std::pair<undirected_graph<VP,EP,GP>::edge_descriptor, bool> |
| 58 | add_edge(undirected_graph<VP,EP,GP> &g |
| 59 | undirected_graph<VP,EP,GP>::vertex_descriptor u, |
| 60 | undirected_graph<VP,EP,GP>::vertex_desrciptor v) |
| 61 | { |
| 62 | return g.add_edge(u, v); |
| 63 | } |
| 64 | }}} |
| 65 | |
| 66 | == Rationale == |
| 67 | This is a much, much simpler template interface to a graph class than presented by `adjacency_list` class. Essentially, we remove almost all of the decision making requirements out of the class by using default arguments for the underlying implementation. Here, the intent is to make get the user working with a graph class (any graph class) as fast as possible. The user really only needs to worry about substituting different containers when performance becomes a requirement. At this point, the user can "simply" redefine the type of thier graphs to an `adjacency_list` as more of an "advanced" feature of the library. Moreover, by selecting `vecS` for both the vertex list and out edge list, we guarantee reasonable performance for a number of common graph problems. |
| 68 | |
| 69 | We do however, leave the property templates in place so users can experiment with adding new properties to vertices and edges and using them with property maps (which isn't very well documented). |
| 70 | |
| 71 | This design, when coupled with improved documentation, should provide |
| 72 | 1. a clear starting point for new users, |
| 73 | 2. a migration from basic, general functionality to advanced and customizable functionality, |
| 74 | 3. and the guarantees type and performance required by the orignal Boost.Graph concepts. |
| 75 | |
| 76 | It might also be worth noticing the re-ordering of parameters to the `add_edge()` method. This aligns with the more convential style of putting the target object fist in the parameter list. |
| 77 | |
| 78 | == Remarks == |
| 79 | I'm actually very fond of this approach since it reduces the interface so much. However, this does leave questions about the `directed_graph`. Specifically, should its directional selection be `directedS` or `bidirectionalS`? My best guess is the latter since it provides more functionality at the expense of space efficiency, but it also makes it more applicable to a wider range of problems. |