1 #ifndef UTOPIA_DATAIO_GRAPH_UTILS_HH
2 #define UTOPIA_DATAIO_GRAPH_UTILS_HH
6 #include <boost/graph/adjacency_list.hpp>
7 #include <boost/graph/adjacency_matrix.hpp>
8 #include <boost/graph/graph_traits.hpp>
9 #include <boost/graph/properties.hpp>
10 #include <boost/hana/all_of.hpp>
11 #include <boost/hana/ext/std/tuple.hpp>
12 #include <boost/hana/for_each.hpp>
16 #include "../core/logging.hh"
17 #include "../core/type_traits.hh"
18 #include "../core/graph/iterator.hh"
22 using namespace std::literals::string_literals;
31 namespace GraphUtilsHelper{
47 template <
typename Graph>
48 std::pair<std::shared_ptr<HDFDataset>,
49 std::shared_ptr<HDFDataset>>
53 const auto num_vertices = boost::num_vertices(g);
54 const auto num_edges = boost::num_edges(g);
57 spdlog::get(
"data_io")->info(
"Saving graph with {} vertices and {} edges "
58 "...", num_vertices, num_edges);
61 auto dset_vertices = grp->open_dataset(
"_vertices", { num_vertices });
62 auto dset_edges = grp->open_dataset(
"_edges", { 2, num_edges });
66 dset_vertices->add_attribute(
"dim_name__0",
"vertex_idx");
67 dset_vertices->add_attribute(
"coords_mode__vertex_idx",
"trivial");
69 dset_edges->add_attribute(
"dim_name__0",
"label");
70 dset_edges->add_attribute(
"coords_mode__label",
"values");
71 dset_edges->add_attribute(
"coords__label",
72 std::vector<std::string>{
"source",
"target"});
73 dset_edges->add_attribute(
"dim_name__1",
"edge_idx");
74 dset_edges->add_attribute(
"coords_mode__edge_idx",
"trivial");
76 return std::make_pair(dset_vertices, dset_edges);
80 template <
typename First,
typename Second,
typename... Tail>
81 constexpr std::tuple<Tail...>
tuple_tail(
const std::tuple<First, Second,
84 return std::apply([](
auto,
auto,
auto... tail) {
85 return std::make_tuple(tail...);}, t);
90 template <
typename CoordT>
93 if constexpr (Utils::is_string_v<CoordT>) {
94 return std::vector<std::string>{};
97 return std::vector<CoordT>{};
138 std::size_t num_entities)
140 static_assert(entity_kind == EntityKind::vertex or
141 entity_kind == EntityKind::edge,
142 "Error, 'entity_kind' has to be either 'vertex' or 'edge'");
146 nw_grp{std::forward<NWGroup>(nw_grp)},
147 label{std::move(label)},
148 it_pair{std::forward<ItPair>(it_pair)},
149 num_entities{std::move(num_entities)}] (
auto&& write_spec)
154 std::string prop_prefix;
156 if constexpr (entity_kind == EntityKind::vertex) {
157 prop_prefix =
"vertex";
160 prop_prefix =
"edge";
164 nw_grp->open_group(std::get<0>(write_spec));
170 std::decay_t<decltype(write_spec)>>>)
172 const auto dset = grp->open_dataset(label, { num_entities });
174 dset->write(it_pair.first, it_pair.second,
176 return std::get<1>(write_spec)(desc, g);
180 dset->add_attribute(
"dim_name__0", prop_prefix +
"_idx");
181 dset->add_attribute(
"coords_mode__"s + prop_prefix +
"_idx",
192 std::decay_t<decltype(write_spec)>>>,
193 "Error, the name of dimension 0 has to be s string");
196 const auto adaptor_pairs =
tuple_tail(write_spec);
201 constexpr
auto num_adaptors = std::tuple_size_v<std::decay_t<
202 decltype(adaptor_pairs)>>;
205 const auto dset = grp->open_dataset(label,
206 {num_adaptors, num_entities});
209 using WriteSpecT = std::decay_t<decltype(write_spec)>;
210 using FirstTupElementT = std::tuple_element_t<2, WriteSpecT>;
211 using CoordT = std::tuple_element_t<0, FirstTupElementT>;
214 auto coords = coords_container<CoordT>();
218 auto apply_adaptor = [&](
auto&& adaptor_pair){
220 dset->write(it_pair.first, it_pair.second,
222 return std::get<1>(adaptor_pair)(desc, g);
229 std::tuple_element_t<0,
230 std::decay_t<decltype(adaptor_pair)>>,
232 "Error, coordinate types do not match! Check that all "
233 "coordinates are of the same type");
235 coords.push_back(std::get<0>(adaptor_pair));
241 const std::string dim0_name = std::get<1>(write_spec);
244 dset->add_attribute(
"dim_name__0", dim0_name);
245 dset->add_attribute(
"coords_mode__"s + dim0_name,
"values");
246 dset->add_attribute(
"coords__"s + dim0_name, coords);
248 dset->add_attribute(
"dim_name__1", prop_prefix +
"_idx");
249 dset->add_attribute(
"coords_mode__"s + prop_prefix +
"_idx",
289 template <
typename Graph>
290 std::shared_ptr<HDFGroup>
292 const std::shared_ptr<HDFGroup>& parent_grp,
293 const std::string& name)
296 auto grp = parent_grp->open_group(name);
298 grp->add_attribute(
"content",
"graph");
301 grp->add_attribute(
"allows_parallel", boost::allows_parallel_edges(g));
306 grp->add_attribute(
"edge_container_is_transposed",
true);
311 "keep_dim", std::vector<std::string>{
"vertex_idx",
"edge_idx"}
314 spdlog::get(
"data_io")->info(
"Opened graph group '{}'.", name);
330 template <
typename Graph>
332 save_graph(
const Graph& g,
const std::shared_ptr<HDFGroup>& grp)
339 auto [v, v_end] = boost::vertices(g);
340 dset_vertices->write(v, v_end, [&](
auto vd) {
341 return boost::get(boost::vertex_index_t(), g, vd);
346 auto [e, e_end] = boost::edges(g);
347 dset_edges->write(e, e_end, [&](
auto ed) {
348 return boost::get(boost::vertex_index_t(), g, boost::source(ed, g));
351 dset_edges->write(e, e_end, [&](
auto ed) {
352 return boost::get(boost::vertex_index_t(), g, boost::target(ed, g));
355 spdlog::get(
"data_io")->debug(
"Graph saved.");
372 template <
typename Graph,
typename PropertyMap>
375 const std::shared_ptr<HDFGroup>& grp,
376 const PropertyMap vertex_ids)
383 auto [v, v_end] = boost::vertices(g);
384 dset_vertices->write(
385 v, v_end, [&](
auto vd) {
return boost::get(vertex_ids, vd); });
389 auto [e, e_end] = boost::edges(g);
390 dset_edges->write(e, e_end, [&](
auto ed) {
391 return boost::get(vertex_ids, boost::source(ed, g));
394 dset_edges->write(e, e_end, [&](
auto ed) {
395 return boost::get(vertex_ids, boost::target(ed, g));
398 spdlog::get(
"data_io")->debug(
"Graph saved.");
448 template <
IterateOver iterate_over,
typename Graph,
typename... Adaptors>
451 const std::shared_ptr<HDFGroup>& nw_grp,
452 const std::string& label,
453 const std::tuple<Adaptors...>& adaptor_tuple)
459 std::tuple_element_t<0, std::decay_t<Adaptors>>>...>,
460 "Error, the first entry of each entry of 'adaptor_tuple' has to be "
461 "string like, to name the adaptor");
464 iterate_over == IterateOver::vertices or
465 iterate_over == IterateOver::edges,
"Error, unknown iterator type! "
466 "Has to be either 'IterateOver::vertices' or 'IterateOver::edges'"
473 auto log = spdlog::get(
"data_io");
479 if constexpr (iterate_over == IterateOver::vertices)
482 const auto num_vertices = boost::num_vertices(g);
485 auto it_pair = GraphUtils::iterator_pair<IterateOver::vertices>(g);
489 auto write_f = generate_write_function<EntityKind::vertex>(
497 log->debug(
"Graph vertex properties saved with label '{}'.", label);
503 const auto num_edges = boost::num_edges(g);
506 auto it_pair = GraphUtils::iterator_pair<IterateOver::edges>(g);
510 auto write_f = generate_write_function<EntityKind::edge>(
518 log->debug(
"Graph edge properties saved with label '{}'.", label);
540 template <
typename Graph,
typename... Adaptors>
543 const std::shared_ptr<HDFGroup>& nw_grp,
544 const std::string& label,
545 const std::tuple<Adaptors...>& adaptor_tuple)
547 save_graph_entity_properties<IterateOver::vertices>(std::forward<Graph>(g),
571 template <
typename Graph,
typename... Adaptors>
574 const std::shared_ptr<HDFGroup>& nw_grp,
575 const std::string& label,
576 const std::tuple<Adaptors...>& adaptor_tuple)
578 save_graph_entity_properties<IterateOver::edges>(std::forward<Graph>(g),
void for_each(const Utopia::ExecPolicy policy, InputIt first, InputIt last, UnaryFunction f)
Apply a function to a range.
Definition: parallel.hh:346
IterateOver
Over which graph entity to iterate.
Definition: iterator.hh:19
void save_graph(const Graph &g, const std::shared_ptr< HDFGroup > &grp, const PropertyMap vertex_ids)
Write function for a boost::Graph.
Definition: graph_utils.hh:374
void save_edge_properties(Graph &&g, const std::shared_ptr< HDFGroup > &nw_grp, const std::string &label, const std::tuple< Adaptors... > &adaptor_tuple)
Definition: graph_utils.hh:573
std::shared_ptr< HDFGroup > create_graph_group(const Graph &g, const std::shared_ptr< HDFGroup > &parent_grp, const std::string &name)
Definition: graph_utils.hh:291
void save_vertex_properties(Graph &&g, const std::shared_ptr< HDFGroup > &nw_grp, const std::string &label, const std::tuple< Adaptors... > &adaptor_tuple)
Definition: graph_utils.hh:542
void save_graph_entity_properties(const Graph &g, const std::shared_ptr< HDFGroup > &nw_grp, const std::string &label, const std::tuple< Adaptors... > &adaptor_tuple)
Definition: graph_utils.hh:450
This is the central file of the HDF5 dataIO module of Utopia and provides a class for writing to,...
This file provides a class for creating and managing groups in a HDF5 file, which then can create oth...
std::pair< std::shared_ptr< HDFDataset >, std::shared_ptr< HDFDataset > > setup_graph_containers(const Graph &g, const std::shared_ptr< HDFGroup > &grp)
Definition: graph_utils.hh:50
auto generate_write_function(const Graph &g, NWGroup &&nw_grp, std::string label, ItPair &&it_pair, std::size_t num_entities)
Definition: graph_utils.hh:134
EntityKind
Kinds of Entities to get properties from.
Definition: graph_utils.hh:102
auto coords_container()
Definition: graph_utils.hh:91
constexpr std::tuple< Tail... > tuple_tail(const std::tuple< First, Second, Tail... > &t)
Builds new tuple containing all elements but the first two.
Definition: graph_utils.hh:81
constexpr bool is_directed()
Check whether the network type allows for directed edges.
Definition: utils.hh:35
constexpr bool is_callable_v
Shorthand for is_callable<T>::value.
Definition: type_traits.hh:734
constexpr bool is_string_v
Shorthand for 'is_string<T>::value'.
Definition: type_traits.hh:140
Check if a type T is a string-like type, i.e. std::basic_string, const char*, char*,...
Definition: type_traits.hh:105