简体   繁体   English

停止Kamada-Kawai布局的条件

[英]Stopping condition for Kamada-Kawai layout

I am using the following code to obtain the Kamada-Kawai layout: 我使用以下代码来获取Kamada-Kawai布局:

template <class PointMap>
PointMap layout() const {
    PointMap res;
    boost::associative_property_map<PointMap> temp(res);

    minstd_rand gen;
    rectangle_topology<> rect_top(gen, 0, 0, 50, 50);
    random_graph_layout(g_, temp, rect_top); // random layout to show that
                                             // Kamada-Kawai isn't doing the job

    // circle_graph_layout(g_, temp, 10.0);

    // http://stackoverflow.com/q/33903879/2725810
    // http://stackoverflow.com/a/8555715/2725810
    typedef std::map<VertexDescriptor, std::size_t> IndexMap;
    IndexMap mapIndex;
    associative_property_map<IndexMap> propmapIndex(mapIndex);
    // http://www.boost.org/doc/libs/1_59_0/libs/graph/doc/bundles.html
    kamada_kawai_spring_layout(
        g_, temp,
        boost::make_transform_value_property_map([](int i)
                                                     ->double { return i; },
                                                 get(edge_bundle, g_)),
        //get(edge_bundle, g_),
        square_topology<>(50.0), side_length(50.0),
        //layout_tolerance<CostType>(0.01),
        kamada_kawai_done(),
        CostType(1), propmapIndex);

    return res;
}

The following types are used: 使用以下类型:

  • The graph type is: 图表类型是:

     boost::adjacency_list<vecS, setS, undirectedS, State, CostType>; 

    where CostType is int . 其中CostTypeint

  • PointMap is: PointMap是:

     std::map<VertexDescriptor, square_topology<>::point_type> 

Here is the stopping condition I am using: 这是我正在使用的停止条件:

struct kamada_kawai_done
{
    kamada_kawai_done() : last_delta() {}

    template<typename Graph>
    bool operator()(double delta_p,
                    typename boost::graph_traits<Graph>::vertex_descriptor /*p*/,
                    const Graph& /*g*/,
                    bool global)
    {
        if (global) {
            double diff = last_delta - delta_p;
            if (diff < 0) diff = -diff;
            std::cout << "delta_p: " << delta_p << std::endl;
            last_delta = delta_p;
            return diff < 0.01;
        } else {
            return delta_p < 0.01;
        }
    }

    double last_delta;
};

Note that it displays delta_p on each iteration. 请注意,它会在每次迭代时显示delta_p

I am running this for a simple graph with only six vertices. 我正在运行这个只有六个顶点的简单图形。 delta_p is displayed only once and it is 0. Given that the initial layout is random, this is really strange. delta_p只显示一次,它是0.鉴于初始布局是随机的,这真的很奇怪。 Here is the picture that I am getting: 这是我得到的图片: 与开罗一起显示的布局

As you can see, the random layout isn't pretty and Kamada-Kawai didn't do a thing with it. 正如你所看到的,随机布局并不漂亮,而Kamada-Kawai并没有做到这一点。

I tried another stopping condition: layout_tolerance<CostType>(0.01) . 我尝试了另一个停止条件: layout_tolerance<CostType>(0.01) This results in Kamada-Kawai running forever. 这导致Kamada-Kawai永远奔跑。

What am I doing wrong here? 我在这做错了什么?

PS: Since I cannot see the picture in my browser, just in case it did not get attached, here is the adjacency structure of the graph. PS:由于我无法在浏览器中看到图片,以防它没有附加,这里是图形的邻接结构。 The graph represents the state space of the Pancake puzzle for the case of three pancakes. 该图表示三个煎饼情况下的煎饼拼图的状态空间。 Namely, the vertices correspond to the different permutations of numbers 0, 1, 2 and there are two edges (all with weight 1) from each vertex: 即,顶点对应于数字0,1,2的不同排列,并且每个顶点有两个边(都具有权重1):

[0, 2, 1]:
    [2, 0, 1] (w=1)
    [1, 2, 0] (w=1)
[2, 0, 1]:
    [0, 2, 1] (w=1)
    [1, 0, 2] (w=1)
[1, 2, 0]:
    [0, 2, 1] (w=1)
    [2, 1, 0] (w=1)
[2, 1, 0]:
    [1, 2, 0] (w=1)
    [0, 1, 2] (w=1)
[1, 0, 2]:
    [2, 0, 1] (w=1)
    [0, 1, 2] (w=1)
[0, 1, 2]:
    [1, 0, 2] (w=1)
    [2, 1, 0] (w=1)

UPDATE : Here is my code to implement the accepted answer: 更新 :这是我的代码,以实现接受的答案:

template <class PointMap> PointMap layout() const {
    PointMap res;

    // Make a copy into a graph that is easier to deal with:
    //     -- vecS for vertex set, so there is index map
    //     -- double for edge weights
    using LayoutGraph =
        boost::adjacency_list<vecS, vecS, undirectedS, int, double>;
    using LayoutVertexDescriptor =
        typename graph_traits<LayoutGraph>::vertex_descriptor;
    std::map<VertexDescriptor, LayoutVertexDescriptor> myMap;
    std::map<LayoutVertexDescriptor, VertexDescriptor> myReverseMap;

    LayoutGraph lg; // This is the copy

    // Copy vertices
    for (auto vd : vertexRange()) {
        auto lvd = add_vertex(lg);
        myMap[vd] = lvd;
        myReverseMap[lvd] = vd;
    }

    // Copy edges
    for (auto from: vertexRange()) {
        for (auto to: adjacentVertexRange(from)) {
            auto lfrom = myMap[from], lto = myMap[to];
            if (!edge(lfrom, lto, lg).second)
                add_edge(lfrom, lto, (double)(g_[edge(to, from, g_).first]),
                         lg);
        }
    }
    // Done copying

    using LayoutPointMap =
        std::map<LayoutVertexDescriptor, square_topology<>::point_type>;
    LayoutPointMap intermediateResults;
    boost::associative_property_map<LayoutPointMap> temp(
        intermediateResults);

    minstd_rand gen;
    rectangle_topology<> rect_top(gen, 0, 0, 100, 100);
    random_graph_layout(lg, temp, rect_top);

    // circle_graph_layout(lg, temp, 10.0);

    kamada_kawai_spring_layout(lg, temp, get(edge_bundle, lg),
                               square_topology<>(100.0), side_length(100.0),
                               //layout_tolerance<CostType>(0.01));
                               kamada_kawai_done());

    for (auto el: intermediateResults)
        res[myReverseMap[el.first]] = el.second;

    return res;
}

For 6 vertices, the layout is a perfect sexagon, so it works! 对于6个顶点,布局是一个完美的sexagon,所以它的工作原理! For 24 vertices, the last displayed delta_p is ~2.25 (shouldn't it be below 0.01?). 对于24个顶点,最后显示的delta_p是~2.25(不应低于0.01?)。 Also, the layout is prettier when starting with the random layout than when starting from the circular one... 此外,从随机布局开始时的布局比从圆形布局开始时更漂亮......

Using a smaller rectangle (eg 20 by 20 instead of 100 by 100) results in a less pretty layout and so does using layout_tolerance<double>(0.01) as a stopping condition. 使用较小的矩形(例如20乘20而不是100乘100)会导致布局不太美观,因此使用layout_tolerance<double>(0.01)作为停止条件。

I think the intermediate approximation may get stored in the actual edge bundle properties, which makes it convert to integer. 我认为中间近似可能存储在实际的边缘束属性中,这使得它转换为整数。

Because of the scale of the input, it apparently loses digits significant for achieving a (local) optimum layout. 由于输入的规模,它显然失去了实现(局部)最佳布局的重要数字。 I'd suggest going with a double for the edge bundle an seeing what happens. 我建议用边缘束加一个看看会发生什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM