Skip to content

Commit ee60c42

Browse files
committed
hypergraph spec fmt support
1 parent 2d44c10 commit ee60c42

7 files changed

Lines changed: 283 additions & 95 deletions

File tree

include/gl/graph.hpp

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -763,30 +763,23 @@ class graph final {
763763
}
764764

765765
std::ostream& _gsf_write(std::ostream& os) const {
766-
using io::detail::option_bit;
766+
using enum io::detail::option_bit;
767767

768-
const bool with_vertex_properties =
769-
io::is_option_set(os, option_bit::with_vertex_properties);
770-
const bool with_edge_properties =
771-
io::is_option_set(os, option_bit::with_connection_properties);
768+
const bool with_v_props = io::is_option_set(os, with_vertex_properties);
769+
const bool with_e_props = io::is_option_set(os, with_connection_properties);
772770

773771
// print graph metadata
774-
os << std::format(
775-
"{} {} {} {} {}\n",
776-
static_cast<int>(traits::c_directed_edge<edge_type>),
777-
this->order(),
778-
this->size(),
779-
static_cast<int>(with_vertex_properties),
780-
static_cast<int>(with_edge_properties)
781-
);
772+
os << traits::c_directed_edge<edge_type> << ' ' << this->order() << ' ' << this->size()
773+
<< ' ' << static_cast<int>(with_v_props) << ' ' << static_cast<int>(with_e_props)
774+
<< '\n';
782775

783776
if constexpr (traits::c_writable<vertex_properties_type>)
784-
if (with_vertex_properties)
777+
if (with_v_props)
785778
for (const auto& vertex : this->vertices())
786779
os << vertex.properties() << '\n';
787780

788781
if constexpr (traits::c_writable<edge_properties_type>) {
789-
if (with_edge_properties) {
782+
if (with_e_props) {
790783
const auto print_out_edges = [this, &os](const id_type vertex_id) {
791784
for (const auto& edge : this->out_edges(vertex_id)) {
792785
if (edge.source() != vertex_id)
@@ -818,16 +811,20 @@ class graph final {
818811
}
819812

820813
std::istream& _gsf_read(std::istream& is) {
821-
bool directed;
822-
is >> directed;
814+
using fmt_traits = io::detail::graph_fmt_traits<directional_tag>;
815+
816+
int dir_discr;
817+
is >> dir_discr;
823818

824-
if (directed != traits::c_directed_edge<edge_type>)
819+
if (dir_discr != fmt_traits::discriminator)
825820
throw std::ios_base::failure(std::format(
826-
"Invalid graph specification: directional tag does not match - should be {}",
827-
fmt_traits::type
821+
"Invalid hypergraph specification: directional specifier {} does not match "
822+
"expected {}",
823+
dir_discr,
824+
fmt_traits::discriminator
828825
));
829826

830-
// read initial graph parameters
827+
// read graph metadata
831828
id_type n_vertices, n_edges;
832829
is >> n_vertices >> n_edges;
833830

include/gl/io/graph_fmt_traits.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ namespace gl::io::detail {
1313
template <typename DirectionalTag>
1414
struct graph_fmt_traits;
1515

16-
template <>
17-
struct graph_fmt_traits<directed_t> {
18-
static constexpr std::string_view type = "directed";
19-
static constexpr std::string_view out_edges = "outgoing edges";
20-
};
21-
2216
template <>
2317
struct graph_fmt_traits<undirected_t> {
18+
static constexpr int discriminator = 0;
2419
static constexpr std::string_view type = "undirected";
2520
static constexpr std::string_view out_edges = "incident edges";
2621
};
2722

23+
template <>
24+
struct graph_fmt_traits<directed_t> {
25+
static constexpr int discriminator = 1;
26+
static constexpr std::string_view type = "directed";
27+
static constexpr std::string_view out_edges = "outgoing edges";
28+
};
29+
2830
} // namespace gl::io::detail

include/hgl/hypergraph.hpp

Lines changed: 175 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
#include "hgl/directional_tags.hpp"
1212
#include "hgl/hypergraph_traits.hpp"
1313
#include "hgl/impl/impl_tags.hpp"
14-
#include "hgl/io.hpp"
14+
#include "hgl/io/core.hpp"
15+
#include "hgl/io/hypergraph_fmt_traits.hpp"
1516
#include "hgl/util.hpp"
1617

1718
#include <algorithm>
@@ -819,15 +820,21 @@ class hypergraph final {
819820
}
820821

821822
friend std::ostream& operator<<(std::ostream& os, const hypergraph& hg) {
822-
// if (gl::io::is_option_set(os, gl::io::detail::option_bit::gsf))
823-
// return hg._gsf_write(os);
823+
using enum io::detail::option_bit;
824+
825+
if (gl::io::is_option_set(os, spec_fmt))
826+
return hg._hgsf_write(os);
824827

825-
if (gl::io::is_option_set(os, gl::io::detail::option_bit::verbose))
828+
if (gl::io::is_option_set(os, verbose))
826829
return hg._verbose_write(os);
827830

828831
return hg._concise_write(os);
829832
}
830833

834+
friend gl_attr_force_inline std::istream& operator>>(std::istream& is, hypergraph& hg) {
835+
return hg._hgsf_read(is);
836+
}
837+
831838
// --- friend declarations ---
832839

833840
template <traits::c_hypergraph Hypergraph>
@@ -991,6 +998,170 @@ class hypergraph final {
991998
return os;
992999
}
9931000

1001+
std::ostream& _hgsf_write(std::ostream& os) const {
1002+
using enum io::detail::option_bit;
1003+
using fmt_traits = io::detail::hypergraph_fmt_traits<directional_tag>;
1004+
1005+
const bool with_v_props = io::is_option_set(os, with_vertex_properties);
1006+
const bool with_he_props = io::is_option_set(os, with_connection_properties);
1007+
1008+
// print hypergraph metadata
1009+
os << fmt_traits::discriminator << ' ' << this->order() << ' ' << this->size() << ' '
1010+
<< static_cast<int>(with_v_props) << ' ' << static_cast<int>(with_he_props) << '\n';
1011+
1012+
if constexpr (traits::c_writable<vertex_properties_type>)
1013+
if (with_v_props)
1014+
for (const auto& vertex : this->vertices())
1015+
os << vertex.properties() << '\n';
1016+
1017+
for (const auto& hyperedge : this->hyperedges()) {
1018+
const auto he_id = hyperedge.id();
1019+
1020+
if constexpr (std::same_as<directional_tag, undirected_t>) {
1021+
os << this->hyperedge_size(he_id);
1022+
for (const auto v : this->incident_vertex_ids(he_id))
1023+
os << ' ' << v;
1024+
}
1025+
else if constexpr (std::same_as<directional_tag, bf_directed_t>) {
1026+
os << this->tail_size(he_id) << ' ' << this->head_size(he_id);
1027+
for (const auto v : this->tail_vertex_ids(he_id))
1028+
os << ' ' << v;
1029+
for (const auto v : this->head_vertex_ids(he_id))
1030+
os << ' ' << v;
1031+
}
1032+
1033+
if constexpr (traits::c_writable<hyperedge_properties_type>) {
1034+
if (with_he_props)
1035+
os << ' ' << hyperedge.properties();
1036+
}
1037+
1038+
os << '\n';
1039+
}
1040+
1041+
return os;
1042+
}
1043+
1044+
std::istream& _hgsf_read(std::istream& is) {
1045+
using fmt_traits = io::detail::hypergraph_fmt_traits<directional_tag>;
1046+
1047+
int dir_discr;
1048+
is >> dir_discr;
1049+
1050+
if (dir_discr != fmt_traits::discriminator)
1051+
throw std::ios_base::failure(std::format(
1052+
"Invalid hypergraph specification: directional specifier {} does not match "
1053+
"expected {}",
1054+
dir_discr,
1055+
fmt_traits::discriminator
1056+
));
1057+
1058+
// read hypergraph metadata
1059+
id_type n_vertices, n_hyperedges;
1060+
is >> n_vertices >> n_hyperedges;
1061+
1062+
bool with_v_props, with_he_props;
1063+
is >> with_v_props >> with_he_props;
1064+
1065+
if (with_v_props) {
1066+
if constexpr (not traits::c_readable<vertex_properties_type>) {
1067+
throw std::ios_base::failure(
1068+
"Invalid hypergraph specification: vertex_properties=true "
1069+
"when vertex_properties_type is not readable"
1070+
);
1071+
}
1072+
else {
1073+
std::vector<vertex_properties_type> vertex_properties(n_vertices);
1074+
for (auto i = 0uz; i < n_vertices; ++i)
1075+
is >> vertex_properties[i];
1076+
this->add_vertices_with(vertex_properties);
1077+
}
1078+
}
1079+
else {
1080+
this->add_vertices(n_vertices);
1081+
}
1082+
1083+
if (with_he_props) {
1084+
if constexpr (not traits::c_readable<hyperedge_properties_type>) {
1085+
throw std::ios_base::failure(
1086+
"Invalid hypergraph specification: hyperedge_properties=true "
1087+
"when hyperedge_properties_type is not readable"
1088+
);
1089+
}
1090+
}
1091+
1092+
this->_read_hyperedges(is, n_hyperedges, with_he_props);
1093+
1094+
return is;
1095+
}
1096+
1097+
void _read_hyperedges(std::istream& is, const size_type n_hyperedges, const bool with_he_props)
1098+
requires std::same_as<directional_tag, undirected_t>
1099+
{
1100+
for (auto _ = 0uz; _ < n_hyperedges; ++_) {
1101+
size_type size;
1102+
is >> size;
1103+
1104+
std::vector<id_type> v_ids(size);
1105+
for (auto i = 0uz; i < size; ++i)
1106+
is >> v_ids[i];
1107+
1108+
id_type new_he_id;
1109+
if constexpr (traits::c_readable<hyperedge_properties_type>) {
1110+
if (with_he_props) {
1111+
hyperedge_properties_type props;
1112+
is >> props;
1113+
new_he_id = this->add_hyperedge_with(std::move(props)).id();
1114+
}
1115+
else {
1116+
new_he_id = this->add_hyperedge().id();
1117+
}
1118+
}
1119+
else {
1120+
new_he_id = this->add_hyperedge().id();
1121+
}
1122+
1123+
for (const auto v_id : v_ids)
1124+
this->bind(v_id, new_he_id);
1125+
}
1126+
}
1127+
1128+
void _read_hyperedges(std::istream& is, const size_type n_hyperedges, const bool with_he_props)
1129+
requires std::same_as<directional_tag, bf_directed_t>
1130+
{
1131+
for (auto _ = 0uz; _ < n_hyperedges; ++_) {
1132+
size_type tail_size, head_size;
1133+
is >> tail_size >> head_size;
1134+
1135+
std::vector<id_type> tail_ids(tail_size);
1136+
for (auto i = 0uz; i < tail_size; ++i)
1137+
is >> tail_ids[i];
1138+
1139+
std::vector<id_type> head_ids(head_size);
1140+
for (auto i = 0uz; i < head_size; ++i)
1141+
is >> head_ids[i];
1142+
1143+
id_type new_he_id;
1144+
if constexpr (traits::c_readable<hyperedge_properties_type>) {
1145+
if (with_he_props) {
1146+
hyperedge_properties_type props;
1147+
is >> props;
1148+
new_he_id = this->add_hyperedge_with(std::move(props)).id();
1149+
}
1150+
else {
1151+
new_he_id = this->add_hyperedge().id();
1152+
}
1153+
}
1154+
else {
1155+
new_he_id = this->add_hyperedge().id();
1156+
}
1157+
1158+
for (const auto v_id : tail_ids)
1159+
this->bind_tail(v_id, new_he_id);
1160+
for (const auto v_id : head_ids)
1161+
this->bind_head(v_id, new_he_id);
1162+
}
1163+
}
1164+
9941165
// --- data members ---
9951166

9961167
size_type _n_vertices = 0uz;

include/hgl/hypergraph_elements.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "gl/types/core.hpp"
88
#include "gl/vertex_descriptor.hpp"
99
#include "hgl/constants.hpp"
10-
#include "hgl/io.hpp"
10+
#include "hgl/io/core.hpp"
1111
#include "hgl/traits.hpp"
1212
#include "hgl/types.hpp"
1313

include/hgl/io.hpp

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,66 +4,4 @@
44

55
#pragma once
66

7-
#include "gl/io/options.hpp"
8-
#include "gl/io/options_manip.hpp"
9-
#include "gl/io/ranges.hpp"
10-
#include "hgl/directional_tags.hpp"
11-
12-
#include <string_view>
13-
14-
namespace hgl::io {
15-
16-
using gl::io::implicit_range;
17-
using gl::io::implicit_range_formatter;
18-
using gl::io::multiline_set_formatter;
19-
using gl::io::range_formatter;
20-
using gl::io::set_formatter;
21-
22-
using gl::io::are_options_set;
23-
using gl::io::clear_options;
24-
using gl::io::is_option_set;
25-
using gl::io::options_manip;
26-
using gl::io::set_options;
27-
28-
namespace detail {
29-
30-
using gl::io::detail::build_mask;
31-
using gl::io::detail::option_bit;
32-
33-
} // namespace detail
34-
35-
using gl::io::concise;
36-
using gl::io::spec_fmt;
37-
using gl::io::verbose;
38-
39-
using gl::io::with_vertex_properties;
40-
using gl::io::without_vertex_properties;
41-
42-
inline const options_manip with_hyperedge_properties =
43-
set_options(detail::option_bit::with_connection_properties);
44-
inline const options_manip without_hyperedge_properties =
45-
clear_options(detail::option_bit::with_connection_properties);
46-
47-
using gl::io::with_properties;
48-
using gl::io::without_properties;
49-
50-
using gl::io::default_options;
51-
52-
namespace detail {
53-
54-
template <typename DirectionalTag>
55-
struct hypergraph_fmt_traits;
56-
57-
template <>
58-
struct hypergraph_fmt_traits<bf_directed_t> {
59-
static constexpr std::string_view type = "BF-directed";
60-
};
61-
62-
template <>
63-
struct hypergraph_fmt_traits<undirected_t> {
64-
static constexpr std::string_view type = "undirected";
65-
};
66-
67-
} // namespace detail
68-
69-
} // namespace hgl::io
7+
#include "hgl/io/core.hpp"

0 commit comments

Comments
 (0)