Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
Enumerations | Functions
Utopia::DataIO::GraphUtilsHelper Namespace Reference

Enumerations

enum class  EntityKind { vertex , edge }
 Kinds of Entities to get properties from. More...
 

Functions

template<typename Graph >
std::pair< std::shared_ptr< HDFDataset >, std::shared_ptr< HDFDataset > > setup_graph_containers (const Graph &g, const std::shared_ptr< HDFGroup > &grp)
 
template<typename First , typename Second , typename... Tail>
constexpr std::tuple< Tail... > tuple_tail (const std::tuple< First, Second, Tail... > &t)
 Builds new tuple containing all elements but the first two.
 
template<typename CoordT >
auto coords_container ()
 
template<EntityKind entity_kind, typename Graph , typename NWGroup , typename ItPair >
auto generate_write_function (const Graph &g, NWGroup &&nw_grp, std::string label, ItPair &&it_pair, std::size_t num_entities)
 

Enumeration Type Documentation

◆ EntityKind

Kinds of Entities to get properties from.

Enumerator
vertex 
edge 

Function Documentation

◆ coords_container()

template<typename CoordT >
auto Utopia::DataIO::GraphUtilsHelper::coords_container ( )

Creates empty vector with element-type CoordT. If CoordT is string-like std::string is enforced

92{
93 if constexpr (Utils::is_string_v<CoordT>) {
94 return std::vector<std::string>{};
95 }
96 else {
97 return std::vector<CoordT>{};
98 }
99}

◆ generate_write_function()

template<EntityKind entity_kind, typename Graph , typename NWGroup , typename ItPair >
auto Utopia::DataIO::GraphUtilsHelper::generate_write_function ( const Graph &  g,
NWGroup &&  nw_grp,
std::string  label,
ItPair &&  it_pair,
std::size_t  num_entities 
)

This function generates a write function for graph entity properties.

The generated lambda function can then be called on each write specification in the adaptor tuple. It writes the specified data to a new dataset and adds attributes, fire-and-forget. Depending on the shape of the write specifications 1d or 2d datasets are written, see Utopia::DataIO::save_graph_entity_properties for more detail. Only relying on the given iterator pair, this function allows to handle vertex and edge iterations equivalently.

Template Parameters
EntityKindThe kind of entity to get the data from. This can be either vertices or edges.
Graph
NWGroup
ItPair
Parameters
gThe graph from which to save vertex or edge properties.
nw_grpThe HDFGroup the data should be written to.
labelThe name of the dataset to which the adaptors write data.
it_pairThe iterator pair used to access the desired entities.
num_entitiesThe number of entities of kind 'EntityKind' in graph g.
Returns
auto The generated write function
139{
140 static_assert(entity_kind == EntityKind::vertex or
141 entity_kind == EntityKind::edge,
142 "Error, 'entity_kind' has to be either 'vertex' or 'edge'");
143
144 return
145 [&g,
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)
150 // By-reference captures are used where possible to avoid additional
151 // copies. Note that this is not possible for label and num_entities.
152 {
153
154 std::string prop_prefix;
155
156 if constexpr (entity_kind == EntityKind::vertex) {
157 prop_prefix = "vertex";
158 }
159 else {
160 prop_prefix = "edge";
161 }
162
163 const auto grp =
164 nw_grp->open_group(std::get<0>(write_spec));
165
166 // ... 1D case if second element of write_spec is a callable object
167 // such that the write specifications are of the form
168 // write_spec = (std::string name_adaptor, lambda adaptor)
169 if constexpr (Utils::is_callable_v<std::tuple_element_t<1,
170 std::decay_t<decltype(write_spec)>>>)
171 {
172 const auto dset = grp->open_dataset(label, { num_entities });
173
174 dset->write(it_pair.first, it_pair.second,
175 [&](auto&& desc) {
176 return std::get<1>(write_spec)(desc, g);
177 }
178 );
179
180 dset->add_attribute("dim_name__0", prop_prefix + "_idx");
181 dset->add_attribute("coords_mode__"s + prop_prefix + "_idx",
182 "trivial");
183 }
184
185 // ... 2D case otherwise
186 // write_spec = (adaptor_name, dim0_name,
187 // (coord1, adaptor1),
188 // (coord2, adaptor2), ...)
189 else {
190
191 static_assert(Utils::is_string_v<std::tuple_element_t<1,
192 std::decay_t<decltype(write_spec)>>>,
193 "Error, the name of dimension 0 has to be s string");
194
195 // Extract the adaptor pairs (coord, adaptor) from write_spec tuple
196 const auto adaptor_pairs = tuple_tail(write_spec);
197 // FIXME This cannot be calculated at compile time since
198 // hana::for_each uses non-constexpr access.
199
200 // Get number of adaptors
201 constexpr auto num_adaptors = std::tuple_size_v<std::decay_t<
202 decltype(adaptor_pairs)>>;
203
204 // Open a 2D dataset
205 const auto dset = grp->open_dataset(label,
206 {num_adaptors, num_entities});
207
208 // Deduce coordinate container type from adaptor_pairs
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>;
212
213 // Create the (empty) coordinates container
214 auto coords = coords_container<CoordT>();
215
216 // Create the lambda that saves the data to the captured
217 // fire-and-forget dataset and stores the coordinate value
218 auto apply_adaptor = [&](auto&& adaptor_pair){
219 // adaptor_pair = (coordinate, adaptor_function)
220 dset->write(it_pair.first, it_pair.second,
221 [&](auto&& desc) {
222 return std::get<1>(adaptor_pair)(desc, g);
223 }
224 );
225
226 static_assert(
227 // assert matching coordinate types
228 std::is_same_v<
229 std::tuple_element_t<0,
230 std::decay_t<decltype(adaptor_pair)>>,
231 CoordT>,
232 "Error, coordinate types do not match! Check that all "
233 "coordinates are of the same type");
234
235 coords.push_back(std::get<0>(adaptor_pair));
236 };
237
238 boost::hana::for_each(adaptor_pairs, apply_adaptor);
239
240 // Extract the 0th dimension name from the write spec
241 const std::string dim0_name = std::get<1>(write_spec);
242
243 // Set attributes
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);
247
248 dset->add_attribute("dim_name__1", prop_prefix + "_idx");
249 dset->add_attribute("coords_mode__"s + prop_prefix + "_idx",
250 "trivial");
251 }
252 };
253}
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

◆ setup_graph_containers()

template<typename Graph >
std::pair< std::shared_ptr< HDFDataset >, std::shared_ptr< HDFDataset > > Utopia::DataIO::GraphUtilsHelper::setup_graph_containers ( const Graph &  g,
const std::shared_ptr< HDFGroup > &  grp 
)

This function opens the vertex and edge datasets for a single graph and adds attributes.

Via the attributes the size of the graph is stored and the trivial coordinates (i.e. vertex idx and edge idx) are added.

Template Parameters
Graph
Parameters
gThe graph to save
grpThe HDFGroup the graph should be stored in
Returns
std::pair<std::shared_ptr<HDFDataset<HDFGroup>>, std::shared_ptr<HDFDataset<HDFGroup>>> Pair containing [vertex dataset, edge dataset]
51{
52 // Collect some information on the graph
53 const auto num_vertices = boost::num_vertices(g);
54 const auto num_edges = boost::num_edges(g);
55
56 // Get a logger to use here (Note: needs to have been setup beforehand)
57 spdlog::get("data_io")->info("Saving graph with {} vertices and {} edges "
58 "...", num_vertices, num_edges);
59
60 // Initialize datasets to store vertices and edges in
61 auto dset_vertices = grp->open_dataset("_vertices", { num_vertices });
62 auto dset_edges = grp->open_dataset("_edges", { 2, num_edges });
63 // NOTE Need shape to be {2, num_edges} because `write` writes line by line.
64
65 // Set attributes
66 dset_vertices->add_attribute("dim_name__0", "vertex_idx");
67 dset_vertices->add_attribute("coords_mode__vertex_idx", "trivial");
68
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");
75
76 return std::make_pair(dset_vertices, dset_edges);
77}

◆ tuple_tail()

template<typename First , typename Second , typename... Tail>
constexpr std::tuple< Tail... > Utopia::DataIO::GraphUtilsHelper::tuple_tail ( const std::tuple< First, Second, Tail... > &  t)
constexpr

Builds new tuple containing all elements but the first two.

83{
84 return std::apply([](auto, auto, auto... tail) {
85 return std::make_tuple(tail...);}, t);
86}