1111#include < algorithm>
1212#include < ranges>
1313#include < vector>
14+ #include < cstdint>
1415
1516#ifdef HGL_TESTING
1617namespace hgl_testing {
@@ -65,16 +66,16 @@ class incidence_matrix<hgl::undirected_t, LayoutTag> final {
6566 [[nodiscard]] gl_attr_force_inline auto incident_hyperedges (const types::id_type vertex_id
6667 ) const noexcept {
6768 if constexpr (std::same_as<layout_tag, impl::vertex_major_t >)
68- return this ->_incident_to_major (vertex_id);
69+ return this ->_incident_with_major (vertex_id);
6970 else
70- return this ->_incident_to_minor (vertex_id);
71+ return this ->_incident_with_minor (vertex_id);
7172 }
7273
7374 [[nodiscard]] types::size_type degree (const types::id_type vertex_id) const noexcept {
7475 if constexpr (std::same_as<layout_tag, impl::vertex_major_t >)
75- return this ->_count_major_bits (vertex_id);
76+ return this ->_count_major (vertex_id);
7677 else
77- return this ->_count_minor_bits (vertex_id);
78+ return this ->_count_minor (vertex_id);
7879 }
7980
8081 // --- hyperedge methods ---
@@ -96,17 +97,17 @@ class incidence_matrix<hgl::undirected_t, LayoutTag> final {
9697 [[nodiscard]] gl_attr_force_inline auto incident_vertices (const types::id_type hyperedge_id
9798 ) const noexcept {
9899 if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t >)
99- return this ->_incident_to_major (hyperedge_id);
100+ return this ->_incident_with_major (hyperedge_id);
100101 else
101- return this ->_incident_to_minor (hyperedge_id);
102+ return this ->_incident_with_minor (hyperedge_id);
102103 }
103104
104105 [[nodiscard]] types::size_type hyperedge_size (const types::id_type hyperedge_id
105106 ) const noexcept {
106107 if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t >)
107- return this ->_count_major_bits (hyperedge_id);
108+ return this ->_count_major (hyperedge_id);
108109 else
109- return this ->_count_minor_bits (hyperedge_id);
110+ return this ->_count_minor (hyperedge_id);
110111 }
111112
112113 // --- binding methods ---
@@ -165,28 +166,28 @@ class incidence_matrix<hgl::undirected_t, LayoutTag> final {
165166 }
166167 }
167168
168- [[nodiscard]] auto _incident_to_major (const types::id_type major_id) const noexcept {
169+ [[nodiscard]] auto _incident_with_major (const types::id_type major_id) const noexcept {
169170 return std::views::iota (0uz, this ->_matrix_row_size )
170171 | std::views::filter ([&row = this ->_matrix [major_id]](const types::id_type minor_id) {
171172 return row[minor_id];
172173 });
173174 }
174175
175- [[nodiscard]] auto _incident_to_minor (const types::id_type minor_id) const noexcept {
176+ [[nodiscard]] auto _incident_with_minor (const types::id_type minor_id) const noexcept {
176177 return std::views::iota (0uz, this ->_matrix .size ())
177178 | std::views::filter ([this , minor_id](const types::id_type major_id) {
178179 return this ->_matrix [major_id][minor_id];
179180 });
180181 }
181182
182- [[nodiscard]] types::size_type _count_major_bits (const types::id_type major_id) const noexcept {
183+ [[nodiscard]] types::size_type _count_major (const types::id_type major_id) const noexcept {
183184 types::size_type count = 0 ;
184185 for (const bool bit : this ->_matrix [major_id])
185186 count += static_cast <types::size_type>(bit);
186187 return count;
187188 }
188189
189- [[nodiscard]] types::size_type _count_minor_bits (const types::id_type minor_id) const noexcept {
190+ [[nodiscard]] types::size_type _count_minor (const types::id_type minor_id) const noexcept {
190191 types::size_type count = 0 ;
191192 for (const auto & row : this ->_matrix )
192193 count += static_cast <types::size_type>(row[minor_id]);
@@ -197,4 +198,198 @@ class incidence_matrix<hgl::undirected_t, LayoutTag> final {
197198 hypergraph_storage_type _matrix;
198199};
199200
201+ template <type_traits::c_hypergraph_layout_tag LayoutTag>
202+ class incidence_matrix <hgl::bf_directed_t , LayoutTag> final {
203+ public:
204+ using layout_tag = LayoutTag;
205+
206+ incidence_matrix (const incidence_matrix&) = delete ;
207+ incidence_matrix& operator =(const incidence_matrix&) = delete ;
208+
209+ incidence_matrix () = default ;
210+
211+ incidence_matrix (const types::size_type n_vertices, const types::size_type n_hyperedges)
212+ : _matrix_row_size{layout_tag::minor (n_vertices, n_hyperedges)},
213+ _matrix (
214+ layout_tag::major (n_vertices, n_hyperedges), matrix_row_type(_matrix_row_size, incidence_type::none)
215+ ) {}
216+
217+ incidence_matrix (incidence_matrix&&) = default;
218+ incidence_matrix& operator =(incidence_matrix&&) = default ;
219+
220+ ~incidence_matrix () = default ;
221+
222+ // --- vertex methods ---
223+
224+ gl_attr_force_inline void add_vertices (const types::size_type n) noexcept {
225+ if constexpr (std::same_as<layout_tag, impl::vertex_major_t >)
226+ this ->_add_major (n);
227+ else
228+ this ->_add_minor (n);
229+ }
230+
231+ gl_attr_force_inline void remove_vertex (const types::id_type vertex_id) noexcept {
232+ if constexpr (std::same_as<layout_tag, impl::vertex_major_t >)
233+ this ->_remove_major (vertex_id);
234+ else
235+ this ->_remove_minor (vertex_id);
236+ }
237+
238+ [[nodiscard]] gl_attr_force_inline auto incident_hyperedges (const types::id_type vertex_id
239+ ) const noexcept {
240+ if constexpr (std::same_as<layout_tag, impl::vertex_major_t >)
241+ return this ->_incident_with_major (vertex_id);
242+ else
243+ return this ->_incident_with_minor (vertex_id);
244+ }
245+
246+ [[nodiscard]] types::size_type degree (const types::id_type vertex_id) const noexcept {
247+ if constexpr (std::same_as<layout_tag, impl::vertex_major_t >)
248+ return this ->_count_major (vertex_id);
249+ else
250+ return this ->_count_minor (vertex_id);
251+ }
252+
253+ // TODO: tail/head-specific variants for incident_hyperedges and degree
254+
255+ // --- hyperedge methods ---
256+
257+ gl_attr_force_inline void add_hyperedges (const types::size_type n) noexcept {
258+ if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t >)
259+ this ->_add_major (n);
260+ else
261+ this ->_add_minor (n);
262+ }
263+
264+ gl_attr_force_inline void remove_hyperedge (const types::id_type hyperedge_id) noexcept {
265+ if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t >)
266+ this ->_remove_major (hyperedge_id);
267+ else
268+ this ->_remove_minor (hyperedge_id);
269+ }
270+
271+ [[nodiscard]] gl_attr_force_inline auto incident_vertices (const types::id_type hyperedge_id
272+ ) const noexcept {
273+ if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t >)
274+ return this ->_incident_with_major (hyperedge_id);
275+ else
276+ return this ->_incident_with_minor (hyperedge_id);
277+ }
278+
279+ [[nodiscard]] types::size_type hyperedge_size (const types::id_type hyperedge_id
280+ ) const noexcept {
281+ if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t >)
282+ return this ->_count_major (hyperedge_id);
283+ else
284+ return this ->_count_minor (hyperedge_id);
285+ }
286+
287+ // TODO: tail/head-specific variants for incident_vertices and hyperedge_size (tail_size, head_size)
288+
289+ // --- binding methods ---
290+
291+ gl_attr_force_inline void bind (
292+ const types::id_type vertex_id, const types::id_type hyperedge_id
293+ ) noexcept {
294+ const auto [major_id, minor_id] = layout_tag::majmin (vertex_id, hyperedge_id);
295+ this ->_matrix [major_id][minor_id] = true ;
296+ }
297+
298+ gl_attr_force_inline void unbind (
299+ const types::id_type vertex_id, const types::id_type hyperedge_id
300+ ) noexcept {
301+ const auto [major_id, minor_id] = layout_tag::majmin (vertex_id, hyperedge_id);
302+ this ->_matrix [major_id][minor_id] = incidence_type::none;
303+ }
304+
305+ [[nodiscard]] gl_attr_force_inline bool are_bound (
306+ const types::id_type vertex_id, const types::id_type hyperedge_id
307+ ) const noexcept {
308+ const auto [major_id, minor_id] = layout_tag::majmin (vertex_id, hyperedge_id);
309+ return this ->_matrix [major_id][minor_id] != incidence_type::none;
310+ }
311+
312+ // TODO: tail/head-specific variants for bind/are_bound
313+
314+ #ifdef HGL_TESTING
315+ friend struct hgl_testing ::test_incidence_matrix;
316+ #endif
317+
318+ private:
319+ enum class incidence_type : std::int8_t {
320+ none = 0 , // v not in E
321+ backward = -1 , // v in T(E)
322+ forward = 1 , // v in H(E)
323+ };
324+
325+ template <typename P>
326+ concept c_incidence_pred = std::predicate<P, incidence_type>;
327+
328+ static constexpr auto _are_incident_pred = [](const incidence_type t) { return t != incidence_type::none; };
329+
330+ using matrix_row_type = std::vector<incidence_type>;
331+ using hypergraph_storage_type = std::vector<matrix_row_type>;
332+
333+ gl_attr_force_inline void _add_major (const types::size_type n) noexcept {
334+ this ->_matrix .resize (
335+ this ->_matrix .size () + n, matrix_row_type (this ->_matrix_row_size , incidence_type::none)
336+ );
337+ }
338+
339+ void _add_minor (const types::size_type n) noexcept {
340+ this ->_matrix_row_size += n;
341+ for (auto & row : this ->_matrix )
342+ row.resize (this ->_matrix_row_size , incidence_type::none);
343+ }
344+
345+ gl_attr_force_inline void _remove_major (const types::id_type major_id) noexcept {
346+ this ->_matrix .erase (this ->_matrix .begin () + major_id);
347+ }
348+
349+ gl_attr_force_inline void _remove_minor (const types::id_type minor_id) noexcept {
350+ if (this ->_matrix_row_size == 0 )
351+ return ;
352+ this ->_matrix_row_size --;
353+ for (auto & row : this ->_matrix )
354+ row.erase (row.begin () + minor_id);
355+ }
356+
357+ [[nodiscard]] auto _incident_with_major (const types::id_type major_id) const noexcept {
358+ return std::views::iota (0uz, this ->_matrix_row_size )
359+ | std::views::filter ([&row = this ->_matrix [major_id]](const types::id_type minor_id) {
360+ return incidence_matrix::_are_incident_pred (row[minor_id]);
361+ });
362+ }
363+
364+ [[nodiscard]] auto _incident_with_minor (const types::id_type minor_id) const noexcept {
365+ return std::views::iota (0uz, this ->_matrix .size ())
366+ | std::views::filter ([this , minor_id](const types::id_type major_id) {
367+ return incidence_matrix::_are_incident_pred (this ->_matrix [major_id][minor_id]);
368+ });
369+ }
370+
371+ [[nodiscard]] types::size_type _count_major (
372+ const types::id_type major_id,
373+ const c_incidence_pred auto pred = incidence_matrix::_are_incident_pred
374+ ) const noexcept {
375+ types::size_type count = 0 ;
376+ for (const incidence_type t : this ->_matrix [major_id])
377+ count += static_cast <types::size_type>(pred (t));
378+ return count;
379+ }
380+
381+ [[nodiscard]] types::size_type _count_minor (
382+ const types::id_type minor_id,
383+ const c_incidence_pred auto pred = incidence_matrix::_are_incident_pred
384+ ) const noexcept {
385+ types::size_type count = 0 ;
386+ for (const auto & row : this ->_matrix )
387+ count += static_cast <types::size_type>(pred (row[minor_id]));
388+ return count;
389+ }
390+
391+ types::size_type _matrix_row_size = 0uz;
392+ hypergraph_storage_type _matrix;
393+ };
394+
200395} // namespace hgl::impl
0 commit comments