Changes between Version 6 and Version 7 of soc/2007/UserFriendlyGraph


Ignore:
Timestamp:
May 14, 2007, 3:46:30 PM (15 years ago)
Author:
Andrew Sutton
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • soc/2007/UserFriendlyGraph

    v6 v7  
    66Since I'm planning on reusing the `adjacency_list<>` for this project, I should point out that its template parameters are in a somewhat strange order. I don't fully understand why the out edge list selector would be first and the edge list selector would be last (even after the vertex, edge and graph properties). I suspect that the edge list was templated as an afterthought and to preserve source code compatibility, it was added to the end of the template parameter list. Still, it's just a little ugly if you actually plan to specialize the class beyond its default types.
    77
    8 I'm going to use the following abbreviations quite frequently:
     8'''Question:''' Should the [un]directed graph classes really allow the override of the underlying collections? If the intent of these classes is to get the users up and running, then perhaps those options could be seen as optimizations rather than algorithm design choices. Since these classes can act as drop-in replacements (and are in fact, implemented in terms of an adjacency list), it should be relatively easy to "upgrade" if the user really needs to change those options. Of course, changing the storage options actually affects properties like iterator and descriptor stability, but that's going to be a gotcha anyways.
     9
     10'''Question:''' Should the [un]directed classes implement or provide checks to ensure that graphs are simple or contain no self-loops? How can this be managed? My gut feeling is that a good answer to this question might be a complete redesign of the graph concept structure. For exmaple, graph properties might be encapsulated in a struct of tags containing items like allow directedness, parallel edge support, self-loop support, etc. This is probably something to think about in the long-term.
     11
     12I'm going to use the following abbreviations for template parameters quite frequently:
    913 * VL - The type of the vertex list. The vertex list stores all of the vertices of the graph.
    1014 * EL - The type of the edge list. Like the vertex list, this stores all the edges in the graph.
     
    1923 * [wiki:soc/2007/UserFriendlyGraphDesignTwo Second Design]
    2024 * [wiki:soc/2007/UserFriendlyGraphDesignThree Third Design]
    21 
    22 An early prototype of the design proposed to simply (publicly) inherit the `adjacency_list` class like so:
    23 {{{
    24 #!cpp
    25 namespace boost {
    26   template <class VL, class EL, class OEL, class VP, class EP, class GP>
    27   class undirected_graph : public adjacency_list<OEL, VL, undirectedS, VP, EP, GP, EL>
    28   { };
    29 }
    30 }}}
    31 Obviously, this probably the simplest implementation possible with as much reuse as possible. In this strategy, I wouldn't even have to implement any of the requirement methods since graphs are always passed by reference, we can let the inheritance handle this for us. The problem with this approach is that if we ever decide to put members into this class, we can run the risk of ''object-slicing'' due to blind reuse of methods that I didn't write. While the alure of a one-line implementation is strong, we should probably defer to practical experience and good advice (in the form of ''C++ Coding Standards: 101 Rules Guidelines and Best Practices'' by Sutter and Alexandrescu). I'm not overloading virtual functions, accessing protected members, and I'm pretty sure `adjacency_list<>` wasn't intended for inheritance.
    32 
    33 A second design approach uses composition as a member rather than private inheritance - not for any particular reason, I'm just more familiar with composition. Now, the prototype looks like this:
    34 {{{
    35 #!cpp
    36 namespace boost {
    37   template <class VL, class EL, class OEL, class VP, class EP, class GP>
    38   class undirected_graph
    39   {
    40     typedef adjacency_list<OEL, VL, undirectedS, VP, EP, GP, EL> graph_type;
    41     graph_type graph;
    42 
    43     public:
    44       graph_type& impl();
    45       const graph_type& impl();
    46 
    47     // other stuff so we comply with graph_traits<>
    48   };
    49 
    50   // example add_vertex() function...
    51   template <class VL, class EL, class OEL, class VP, class EP, class GP>
    52   undirected_graph<VL, EL, OEL, VP, EP, GP>::vertex_descriptor
    53   add_vertex(undirected_graph<VL, EL, OEL, VP, EP, GP> &g)
    54   {
    55     return add_vertex(g.impl());  // calls add_vertex() for adjacency_list
    56   }
    57 }
    58 }}}
    59 Clearly a very different approach, but once complete it should preserve all of the concept requirements given in the documentation. Interestingly, this is somewhat similar to graph adapter classes except that we aren't really adapting the adjacency list to a different purpose - we're just reducing the "abstractness" of the class by requiring (in this case), that it is instantiated with the `undirectedS` parameter. This approach is also a little more flexible than the previous in that we can add to this class without fear of unexpected consequences in the details of the original implementation. Of course, with this I'll have to write more code.
    60 
    61 '''Question:''' Should the [un]directed graph classes really allow the override of the underlying collections? If the intent of these classes is to get the users up and running, then perhaps those options could be seen as optimizations rather than algorithm design choices. Since these classes can act as drop-in replacements (and are in fact, implemented in terms of an adjacency list), it should be relatively easy to "upgrade" if the user really needs to change those options. Of course, changing the storage options actually affects properties like iterator and descriptor stability, but that's going to be a gotcha anyways.
    62 
    63 '''Question:''' Should the [un]directed classes implement or provide checks to ensure that graphs are simple or contain no self-loops? How can this be managed? My gut feeling is that a good answer to this question might be a complete redesign of the graph concept structure. For exmaple, graph properties might be encapsulated in a struct of tags containing items like allow directedness, parallel edge support, self-loop support, etc. This is probably something to think about in the long-term.
    6425
    6526== Measures and Algorithms ==