Ouput (для GraphViz) Повысить вершины графа с помощью их свойства, используя в качестве связанного свойства класс с закрытыми переменными - PullRequest
0 голосов
/ 06 июня 2018

Я использую усиленный ориентированный граф с настраиваемым классом в качестве связанного свойства для вершин и хочу распечатать его в формате DOT с помощью graphviz.У класса есть закрытая переменная, значение которой я хочу отобразить в файле DOT.

Пример кода, демонстрирующий мою проблему:

#include <iostream>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/property_map/transform_value_property_map.hpp>

class VertexClass
{
public:
    VertexClass() { id = 12; }
    VertexClass( int newId ) { id = newId; }
    int get_id() { return id; }
    void set_id( int newId ) { id = newId; }
private:
    int id;
};

typedef boost::directed_graph<VertexClass, boost::no_property> Graph;

int main(int,char*[])
{
    Graph g;

    Graph::vertex_descriptor v0 = g.add_vertex(3);
    Graph::vertex_descriptor v1 = g.add_vertex(5);
    Graph::vertex_descriptor v2 = g.add_vertex(6);

    boost::add_edge(v0,v1,g);
    boost::add_edge(v1,v2,g);

    //boost::write_graphviz(std::cout, g, ...);

    return 0;
}

Желаемый вывод:

digraph G {
0[label=3];
1[label=5];
2[label=6];
0->1 ;
1->2 ;
}

(получено, сделав "id" публичным и запустив код ниже).

Теперь, "id" является приватным, поэтому приведенный ниже код (который я нашел, читая другие подобные вопросы) не будет работать для меня:

boost::write_graphviz(std::cout, g, boost::make_label_writer(boost::get(&VertexClass::id, g)));

Я думаю, мне нужно использовать аксессор, чтобы получить идентификатор.После небольшого поиска я обнаружил, что некоторые люди предлагают использовать карту свойств преобразования значений (make_transform_value_property_map).

Тогда я нашел этот ответ .Но проблема в том, что в этом случае свойство определяется не как связанное, а с использованием enum и BOOST_INSTALL_PROPERTY.Так как у меня нет этих тегов, которые предоставляет этот метод (и мне было бы сложно переключать методы, так как мой реальный код более сложный), он не работает для меня (или, по крайней мере, я не знаю,как это сделать).

Далее, прочитав этот ответ Я попробовал следующее:

boost::write_graphviz(std::cout, g, boost::make_label_writer(boost::make_transform_value_property_map(&VertexClass::get_id, boost::get(boost::vertex_bundle, g))));

, но я получаю следующую ошибку (полный вывод ниже):

$ g++ -Wall -std=c++11 main.cpp
In file included from /usr/local/include/boost/graph/directed_graph.hpp:13:0,
                 from main.cpp:2:
/usr/local/include/boost/property_map/transform_value_property_map.hpp: In instantiation of ‘boost::transform_value_property_map<Func, PM, Ret>::reference boost::transform_value_property_map<Func, PM, Ret>::operator[](const key_type&) const [with Func = int (VertexClass::*)(); PM = boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>; Ret = int; boost::transform_value_property_map<Func, PM, Ret>::reference = int; boost::transform_value_property_map<Func, PM, Ret>::key_type = void*]’:
/usr/local/include/boost/property_map/property_map.hpp:303:54:   required from ‘Reference boost::get(const boost::put_get_helper<Reference, PropertyMap>&, const K&) [with PropertyMap = boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>; Reference = int; K = void*]’
/usr/local/include/boost/graph/graphviz.hpp:85:56:   required from ‘void boost::label_writer<Name>::operator()(std::ostream&, const VertexOrEdge&) const [with VertexOrEdge = void*; Name = boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>; std::ostream = std::basic_ostream<char>]’
/usr/local/include/boost/graph/graphviz.hpp:270:18:   required from ‘void boost::write_graphviz(std::ostream&, const Graph&, VertexPropertiesWriter, EdgePropertiesWriter, GraphPropertiesWriter, VertexID, typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type) [with Graph = boost::directed_graph<VertexClass, boost::no_property>; VertexPropertiesWriter = boost::label_writer<boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int> >; EdgePropertiesWriter = boost::default_writer; GraphPropertiesWriter = boost::default_writer; VertexID = boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, unsigned int, const unsigned int&, boost::vertex_index_t>; std::ostream = std::basic_ostream<char>; typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type = boost::graph::detail::no_parameter]’
/usr/local/include/boost/graph/graphviz.hpp:290:63:   required from ‘void boost::write_graphviz(std::ostream&, const Graph&, VertexPropertiesWriter, EdgePropertiesWriter, GraphPropertiesWriter, typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type) [with Graph = boost::directed_graph<VertexClass, boost::no_property>; VertexPropertiesWriter = boost::label_writer<boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int> >; EdgePropertiesWriter = boost::default_writer; GraphPropertiesWriter = boost::default_writer; std::ostream = std::basic_ostream<char>; typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type = boost::graph::detail::no_parameter]’
/usr/local/include/boost/graph/graphviz.hpp:309:38:   required from ‘void boost::write_graphviz(std::ostream&, const Graph&, VertexWriter, typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type) [with Graph = boost::directed_graph<VertexClass, boost::no_property>; VertexWriter = boost::label_writer<boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int> >; std::ostream = std::basic_ostream<char>; typename boost::enable_if_c<boost::is_base_and_derived<boost::vertex_list_graph_tag, typename boost::graph_traits<Graph>::traversal_category>::value, boost::graph::detail::no_parameter>::type = boost::graph::detail::no_parameter]’
main.cpp:30:166:   required from here
/usr/local/include/boost/property_map/transform_value_property_map.hpp:45:24: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘((const boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>*)this)->boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>::f (...)’, e.g. ‘(... ->* ((const boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>*)this)->boost::transform_value_property_map<int (VertexClass::*)(), boost::adj_list_vertex_property_map<boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boost::property<boost::vertex_index_t, unsigned int, VertexClass>, boost::property<boost::edge_index_t, unsigned int, boost::no_property>, boost::no_property, boost::listS>, VertexClass, VertexClass&, boost::vertex_bundle_t>, int>::f) (...)’
     return f(get(pm, k));

Каждый вопрос / ответ, который я видел, касается одного из двух упомянутых выше случаев (связанные свойства с открытыми переменными (например, структурами) или устаревшее объявление свойства).

Я новичок в буст-библиотеке графов, так что, наверное, я что-то пропустил.Но я не могу найти решение (и действительно потерялся в документации Boost), поэтому любая помощь будет высоко ценится.

1 Ответ

0 голосов
/ 06 июня 2018

Включение для transform_value_property_map указывает мне, что вы были близки к решению.Вот оно:

boost::dynamic_properties dp;

Во-первых, давайте заявим, что вы хотите иметь внутренний индекс вершины для идентификаторов узла graphviz:

dp.property("node_id", get(boost::vertex_index, g));

Теперь мы хотим сделать что-то с пакетом, поэтомудавайте возьмем карту свойств для всего пакета:

auto vbundle = get(boost::vertex_bundle, g);

Но мы не можем использовать его напрямую.Нам нужно его преобразовать:

dp.property("label", 
        boost::make_transform_value_property_map([](VertexClass const& vd) {
            return vd.get_id();
            }, vbundle));

Примечание!Я сделал get_id() const константой, чтобы сделать эту компиляцию

Теперь напишите:

boost::write_graphviz_dp(std::cout, g, dp);

Результат:

Live On Coliru

digraph G {
0 [label=3];
1 [label=5];
2 [label=6];
0->1 ;
1->2 ;
}

Альтернатива # 1

В этом случае вы могли бы сойти с рук проще:

Live On Coliru

dp.property("label", 
    boost::make_transform_value_property_map(std::mem_fn(&VertexClass::get_id), vbundle));

вместо более гибкой лямбды

Альтернатива № 2: Нет квази-Классы

Вы, похоже, попали в ловушку, требуя квази-классов ( PDF ), где они не добавляют никакой ценности.Упрощение:

Live On Coliru

#include <boost/graph/directed_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <iostream>

struct VertexProps { int id; };
typedef boost::directed_graph<VertexProps> Graph;

int main() {
    Graph g;
    auto v1 = add_vertex({5}, g);

    add_edge(add_vertex({3}, g), v1, g);
    add_edge(v1, add_vertex({6}, g), g);

    boost::dynamic_properties dp;
    dp.property("node_id", get(boost::vertex_index, g));
    dp.property("label", get(&VertexProps::id, g));

    write_graphviz_dp(std::cout, g, dp);
}

Как вы можете видеть, теперь все сокращается до 20 строккода с первоклассной поддержкой ваших свойств вершин.

...