Boost.Graph:保存并加载一个名为Boost::adjacety_list的列表

Boost.Graph: saving and loading a boost::adjacency_list with a name

本文关键字:Boost adjacety list 列表 一个 保存 Graph 加载      更新时间:2023-10-16

对于boost::adjaceny_list,我能够获取并设置图形的名称。遗憾的是,我无法将其保存并加载到文件中。我可以保存和加载顶点和边,但图形属性的工作方式不同。

在下面完整的测试编译代码中,我展示了:

  • 如何创建具有名称的空有向图
  • 设置并获取图形的名称
  • 加载并保存图形
  • main:设置一个图形的名称,保存,加载,检查结果是否仍然具有该名称

首先是基础:

  • 如何创建具有名称的空有向图
  • 设置并获取图形的名称

这些函数非常简短:

#include <boost/graph/adjacency_list.hpp>
#include <string>
boost::adjacency_list<
  boost::vecS,
  boost::vecS,
  boost::directedS,
  boost::no_property,
  boost::no_property,
  boost::property<boost::graph_name_t,std::string>
>
create_empty_directed_graph_with_graph_name() noexcept
{
  return {};
}
template <typename graph>
void set_graph_name(const std::string& name, graph& g) noexcept
{
  get_property(g, boost::graph_name) = name;
}
template <typename graph>
std::string get_graph_name(const graph& g) noexcept
{
  return get_property(g, boost::graph_name
  );
}

我想开始工作的测试:

int main()
{
  const std::string dot_filename{"test.dot"};
  auto g = create_empty_directed_graph_with_graph_name();
  set_graph_name("TestGraph", g);
  save_graph_with_graph_name_to_dot(g, dot_filename);
  const auto h = load_directed_graph_with_graph_name_from_dot(dot_filename);
  assert(get_graph_name(g) == get_graph_name(h));
}

步骤是:(1)设置一个图形的名称(2)保存它(3)加载一个图形(4)检查它是否具有相同的名称

我质疑的代码是保存。我用这样的名称保存图形:

template <typename graph>
void save_graph_with_graph_name_to_dot(
  const graph& g, const std::string& filename
)
{
  std::ofstream f(filename);
  boost::write_graphviz(
    f,
    g,
    boost::default_writer(),
    boost::default_writer(),
    [g](std::ostream& os) {
      os << "name=""
        << get_graph_name(g)
        << "";n";
    }
  );
}

我不确定这是不是该走的路。它生成以下.dot文件:

digraph G {
name="TestGraph";
}

我想知道它是否不应该说"有向图测试图",但它被接受为一个有效的.dot文件。

加载这个文件是我陷入困境的地方。我甚至不知道如何编译它。我知道如何(保存和)加载任何类型的边和顶点(请参阅Boost.Graph教程),但在这里我迷失了方向。这是我的尝试:

boost::adjacency_list<
  boost::vecS,
  boost::vecS,
  boost::directedS,
  boost::no_property,
  boost::no_property,
  boost::property<boost::graph_name_t, std::string>
>
load_directed_graph_with_graph_name_from_dot(
  const std::string& dot_filename
)
{
  std::ifstream f(dot_filename.c_str());
  auto g = create_empty_directed_graph_with_graph_name();
  //#define TODO_KNOW_HOW_TO_LOAD_A_GRAPH_ITS_NAME
  #ifdef TODO_KNOW_HOW_TO_LOAD_A_GRAPH_ITS_NAME
  boost::dynamic_properties p;
  p.property("name",get_property(g,boost::graph_name)); //Something like this?
  #else
  boost::dynamic_properties p(
    boost::ignore_other_properties
  );
  #endif
  boost::read_graphviz(f,g,p);
  return g;
}

我希望有人知道如何保存和加载带有名称的图形。应该不会太难吧?

以下是完整的列表:

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/properties.hpp>
#include <cassert>
#include <fstream>
#include <string>
boost::adjacency_list<
  boost::vecS,
  boost::vecS,
  boost::directedS,
  boost::no_property,
  boost::no_property,
  boost::property<boost::graph_name_t,std::string>
>
create_empty_directed_graph_with_graph_name() noexcept
{
  return {};
}
template <typename graph>
void set_graph_name(const std::string& name, graph& g) noexcept
{
  get_property(g, boost::graph_name) = name;
}
template <typename graph>
std::string get_graph_name(const graph& g) noexcept
{
  return get_property(g, boost::graph_name
  );
}
template <typename graph>
void save_graph_with_graph_name_to_dot(
  const graph& g, const std::string& filename
)
{
  std::ofstream f(filename);
  boost::write_graphviz(
    f,
    g,
    boost::default_writer(),
    boost::default_writer(),
    //Unsure if this results in a graph that can be loaded correctly from a .dot file
    [g](std::ostream& os) {
      os << "name=""
        << get_graph_name(g)
        << "";n";
    }
  );
}
boost::adjacency_list<
  boost::vecS,
  boost::vecS,
  boost::directedS,
  boost::no_property,
  boost::no_property,
  boost::property<boost::graph_name_t, std::string>
>
load_directed_graph_with_graph_name_from_dot(
  const std::string& dot_filename
)
{
  std::ifstream f(dot_filename.c_str());
  auto g = create_empty_directed_graph_with_graph_name();
  //#define TODO_KNOW_HOW_TO_LOAD_A_GRAPH_ITS_NAME
  #ifdef TODO_KNOW_HOW_TO_LOAD_A_GRAPH_ITS_NAME
  boost::dynamic_properties p;
  p.property("name",get_property(g,boost::graph_name)); //Something like this?
  #else
  boost::dynamic_properties p(
    boost::ignore_other_properties
  );
  #endif
  boost::read_graphviz(f,g,p);
  return g;
}
int main()
{
  const std::string dot_filename{"test.dot"};
  auto g = create_empty_directed_graph_with_graph_name();
  set_graph_name("TestGraph", g);
  save_graph_with_graph_name_to_dot(g, dot_filename);
  const auto h = load_directed_graph_with_graph_name_from_dot(dot_filename);
  assert(get_graph_name(g) == get_graph_name(h));
}

cv_and_he:谢谢!我确实看到了那一页,但读起来很吃力!

答:代码的加载部分需要更改为:

boost::adjacency_list<
  boost::vecS,
  boost::vecS,
  boost::directedS,
  boost::no_property,
  boost::no_property,
  boost::property<boost::graph_name_t, std::string>
>
load_directed_graph_with_graph_name_from_dot(
  const std::string& dot_filename
)
{
  using graph = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::directedS,
    boost::no_property,
    boost::no_property,
    boost::property<boost::graph_name_t, std::string>
  >;

  std::ifstream f(dot_filename.c_str());
  auto g = create_empty_directed_graph_with_graph_name();
  boost::ref_property_map<graph*,std::string>
    graph_name(get_property(g,boost::graph_name)
  );
  boost::dynamic_properties dp;
  dp.property("name",graph_name);
  boost::read_graphviz(f,g,dp);
  return g;
}