c++boostboost-graphboost-property-map

Boost::Graph-algorithm does not write data with PropertyMap (kamada_kawai_spring_layout, bundled properties)


I have a an adjacency_list graph with randomly connected nodes using Erdos-Renyi edge generation. The graph uses bundled properties by defining data structures both for the vertices (Graph_Node) and edges (Graph_Edge), which is used to assign the position of the nodes and the weights of the edges.

I'm trying to use force-directed graph drawing to assign good positions for the nodes, using kamada_kawai_spring_layout.

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/erdos_renyi_generator.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/graph/kamada_kawai_spring_layout.hpp>

using namespace boost;
struct Graph_Node
{
    typedef convex_topology<2>::point tPoint;
    tPoint Position;

};
struct Graph_Edge
{
    unsigned int ID;
    double weight = 100.;
};

typedef adjacency_list<vecS, vecS, undirectedS, Graph_Node, Graph_Edge> Graph;
static random::minstd_rand rng;
typedef erdos_renyi_iterator<random::minstd_rand, Graph> ERGen;
static const int ER_INIT_NODES = 50;
static const double p = 0.05;
static Graph g(ERGen(rng, ER_INIT_NODES, p), ERGen(), ER_INIT_NODES);

int main()
{
    ball_topology<2> T(1.);
    detail::graph::edge_or_side<1, double> scaling(1.);
    kamada_kawai_spring_layout(g, get(&Graph_Node::Position, g), get(&Graph_Edge::weight, g), T, scaling);
    Graph::vertex_iterator v, v_end;
    for (std::tie(v, v_end) = vertices(g); v != v_end; ++v)
        std::cout << g[*v].Position[0] << ", " << g[*v].Position[1] << std::endl;
}

Graph_Node::Position is intended to be assigned using kamada_kawai_spring_layout, but the Position of all the vertices in g are 0,0 after assignment. Why?


Solution

  • The return value of the algorithm:

    Returns: true if layout was successful or false if a negative weight cycle was detected or the graph is disconnected.

    When you print it, you'll see that it is false. So, your graph doesn't satisfy the requirements.

    Raising the edge probability makes for connected graphs:

    Live On Compiler Explorer

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/circle_layout.hpp>
    #include <boost/graph/erdos_renyi_generator.hpp>
    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/kamada_kawai_spring_layout.hpp>
    #include <boost/random/linear_congruential.hpp>
    #include <fmt/ranges.h>
    
    using tPoint = boost::convex_topology<2>::point;
    struct Graph_Node { tPoint Position{}; };
    struct Graph_Edge { /*unsigned int ID;*/ double weight = 100; };
    
    using Graph = boost::adjacency_list<boost::vecS, boost::vecS,
                                        boost::undirectedS, Graph_Node, Graph_Edge>;
    
    static constexpr int    ER_INIT_NODES = 20; // 50
    static constexpr double p             = 1;  // 0.05
    
    Graph make_graph() {
        boost::random::minstd_rand rng;
        using Gen = boost::erdos_renyi_iterator<boost::random::minstd_rand, Graph>;
        return {Gen(rng, ER_INIT_NODES, p), Gen(), ER_INIT_NODES};
    }
    
    int main()
    {
        auto g = make_graph();
        //write_graphviz(std::cout, g);
    
        auto print_position = [pos = get(&Graph_Node::Position, g)](size_t v) {
            fmt::print("Vertex {:3} Position {:9.4f}, {:9.4f}\n", v, pos[v][0], pos[v][1]);
        };
    
        auto mid_vertex = vertex(ER_INIT_NODES / 2, g);
        print_position(mid_vertex);
        boost::circle_graph_layout(g, get(&Graph_Node::Position, g), 25.0);
    
        if (true) { // ball-topology
            print_position(mid_vertex);
    
            bool ok = kamada_kawai_spring_layout(                    //
                g,                                                   //
                get(&Graph_Node::Position, g),                       //
                get(&Graph_Edge::weight, g),                         //
                boost::ball_topology<2>(1.),                         //
                boost::detail::graph::edge_or_side<true, double>(1.) //
            );
            fmt::print("kamada_kawai_spring_layout ok: {}\n", ok);
        } else {
            print_position(mid_vertex);
            bool ok = kamada_kawai_spring_layout( //
                g,                                //
                get(&Graph_Node::Position, g),    //
                get(&Graph_Edge::weight, g),      //
                boost::square_topology<>(50.0),   //
                boost::side_length(50.0)          //
            );
            fmt::print("kamada_kawai_spring_layout ok: {}\n", ok);
        }
    
        print_position(mid_vertex);
        fmt::print("----\n");
        for (auto v : boost::make_iterator_range(vertices(g)))
            print_position(v);
    }
    

    Prints

    Vertex  10 Position    0.0000,    0.0000
    Vertex  10 Position  -25.0000,    0.0000
    kamada_kawai_spring_layout ok: true
    Vertex  10 Position   20.3345, -102.5760
    ----
    Vertex   0 Position  -35.8645,  -19.4454
    Vertex   1 Position  -72.7690, -130.3436
    Vertex   2 Position   -8.5828, -138.2843
    Vertex   3 Position  -44.7830,  -52.9697
    Vertex   4 Position  -43.0101,   30.9041
    Vertex   5 Position  -69.7531,   38.7188
    Vertex   6 Position   -0.4328,   43.2208
    Vertex   7 Position   31.3758,  -30.9816
    Vertex   8 Position   47.1809,   12.8283
    Vertex   9 Position  -76.9535,    9.7684
    Vertex  10 Position   20.3345, -102.5760
    Vertex  11 Position  -19.5602, -103.9834
    Vertex  12 Position  -68.2476,  -78.6953
    Vertex  13 Position  -95.3881,  -46.8710
    Vertex  14 Position -131.4928,    7.9270
    Vertex  15 Position   24.0966,   -4.9534
    Vertex  16 Position   59.0794,  -86.1642
    Vertex  17 Position -102.4687, -148.9986
    Vertex  18 Position  -10.8986,  -52.8234
    Vertex  19 Position -131.8706,  -60.2588