Search code examples
c++graphboost

What is a Simple Example for using the Boost Graph Library


I am trying to use the BGL, I find the documentation precise but lacks more examples for simple cases. My goal is described below (after reading the documentation I still couldn't do this):

struct Vertex
{
    double m_d;
    std::size_t m_id;
};

//or

struct Vertex
{
    double m_d;
    std::size_t id() const;
};

Goals:

  1. A directed graph G (what is the difference between a bidirectional and directed other than in_edges please?)
  2. G can hold the vertex type Vertex.
  3. get the vertex by id from G and change the value m_d in the Vertex struct when I want.
  4. add, remove verticies and edges between verticies and also supports costs i.e. cost(edge).

Could you please write me an example on how to do this with BGL please? I beleive I need MutableBidirectionalGraph?


Solution

    1. A directed graph G

      Straight-away:

      struct Vertex {
          double m_d  = 0;
          size_t m_id = -1;
          // or std::size_t id() const;
      };
      
      struct Edge {
          double cost = 0;
      };
      
      using Graph =
          boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge>;
      

      (what is the difference between a bidirectional and directed other than in_edges please?)

      There is no other difference, except of course the complexity guarantees for enumerating incoming edges, and a linear overhead upon insertion of edges

    2. G can hold the vertex type Vertex.

      See 0.

    3. get the vertex by id from G

          auto find_by_id = [&g](size_t id) -> Vertex& {
              auto vv = boost::make_iterator_range(vertices(g));
              auto vd = find_if(vv, [&, id](auto vd) { return g[vd].m_id == id; });
              return g[*vd];
          };
      

      and change the value m_d in the Vertex struct when I want.

      if (i_want()) {
          g[vd].m_id += 1;
      }
      

      Or,

      auto idmap = boost::get(&Vertex::m_id, g);
      
      if (i_want()) {
          idmap[vd] += 1;
      }
      

      or even

      put(idmap, vd, 42);
      

      or even more unmarked:

      get(boost::vertex_bundle, g, vd).m_id = 999;
      
    4. add, remove vertices

       remove_vertex(vd, g);
      

      and edges between vertices

       clear_vertex(vd, g);
      

      and also supports costs i.e. cost(edge).

      Wow that really has nothing to do with any of the above. But it's really the same as with vertex ids:

      if (i_want()) {
          g[ed].cost = new_cost;
      }
      

      Or,

      auto cost = boost::get(&Edge::cost, g);
      
      if (i_want()) {
          cost[ed] = new_cost;
      }
      

      or even

      put(cost, ed, new_cost);
      

      or even more unmarked:

      get(boost::edge_bundle, g, ed).cost = new_cost;
      

    Live Demo

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/graph_utility.hpp>
    #include <boost/range/algorithm.hpp>
    #include <iostream>
    
    struct Vertex {
        double m_d  = 0;
        size_t m_id = -1;
        // or std::size_t id() const;
    };
    
    struct Edge {
        double cost = 0;
    };
    
    using Graph =
        boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge>;
    
    using boost::make_iterator_range;
    
    int main(){
        Graph g;
        auto v0 = add_vertex({0.1, 100}, g);
        auto v1 = add_vertex({0.2, 200}, g);
        auto v2 = add_vertex({0.3, 300}, g);
        auto v3 = add_vertex({0.4, 400}, g);
        auto v4 = add_vertex({0.5, 500}, g);
        auto v5 = add_vertex({0.6, 600}, g);
    
        add_edge(v0, v2, Edge{1.5}, g);
        add_edge(v1, v3, Edge{2.5}, g);
        add_edge(v4, v1, Edge{3.5}, g);
        add_edge(v2, v5, Edge{4.5}, g);
    
        auto idmap = boost::get(&Vertex::m_id, g);
        auto cost  = boost::get(&Edge::cost, g);
    
        auto find_by_id = [&g](size_t id) -> Vertex& {
            auto vv = boost::make_iterator_range(vertices(g));
            auto vd = find_if(vv, [&, id](auto vd) { return g[vd].m_id == id; });
            return g[*vd];
        };
    
        print_graph(g, idmap, std::cout << "original: ");
    
        auto i_want = [](auto vd) {
            return (vd % 2); // when I want
        };
    
        for (auto vd : make_iterator_range(vertices(g))) {
            if (i_want(vd))
                g[vd].m_id += 1;
            if (i_want(vd))
                idmap[vd] += 1;
            //put(idmap, vd, 42);
            //get(boost::vertex_bundle, g, vd).m_id = 999;
        }
    
        print_graph(g, idmap, std::cout << "altered: ");
    
        clear_vertex(v3, g);
        remove_vertex(v3, g); // undefined behaviour unless edges cleared
    
        print_graph(g, idmap, std::cout << "removed: ");
    
        for (auto ed : make_iterator_range(edges(g))) {
            std::cout << ed << " cost " << cost[ed] << "\n";
        }
    
        for (auto ed : make_iterator_range(edges(g))) {
            cost[ed] *= 111;
        }
    
        for (auto ed : make_iterator_range(edges(g))) {
            std::cout << ed << " cost " << cost[ed] << "\n";
        }
    };
    

    Prints

    original: 100 --> 300 
    200 --> 400 
    300 --> 600 
    400 --> 
    500 --> 200 
    600 --> 
    altered: 100 --> 300 
    202 --> 402 
    300 --> 602 
    402 --> 
    500 --> 202 
    602 --> 
    removed: 100 --> 300 
    202 --> 
    300 --> 602 
    500 --> 202 
    602 --> 
    (0,2) cost 1.5
    (3,1) cost 3.5
    (2,4) cost 4.5
    (0,2) cost 166.5
    (3,1) cost 388.5
    (2,4) cost 499.5