Jonas Hjulstad
Jonas Hjulstad

Reputation: 415

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?

Upvotes: 1

Views: 69

Answers (1)

sehe
sehe

Reputation: 392911

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

Upvotes: 2

Related Questions