Skip to content

Commit c485bbe

Browse files
committed
initial draft of the bf-directed matrix model
1 parent bcbe88d commit c485bbe

2 files changed

Lines changed: 213 additions & 18 deletions

File tree

include/hgl/impl/incidence_list.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ class incidence_list<hgl::undirected_t, LayoutTag> final {
6060
[[nodiscard]] gl_attr_force_inline auto incident_hyperedges(const types::id_type vertex_id
6161
) const noexcept {
6262
if constexpr (std::same_as<layout_tag, impl::vertex_major_t>)
63-
return this->_incident_to_major(vertex_id);
63+
return this->_incident_with_major(vertex_id);
6464
else
65-
return this->_incident_to_minor(vertex_id);
65+
return this->_incident_with_minor(vertex_id);
6666
}
6767

6868
[[nodiscard]] gl_attr_force_inline types::size_type degree(const types::id_type vertex_id
@@ -90,9 +90,9 @@ class incidence_list<hgl::undirected_t, LayoutTag> final {
9090
[[nodiscard]] gl_attr_force_inline auto incident_vertices(const types::id_type hyperedge_id
9191
) const noexcept {
9292
if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t>)
93-
return this->_incident_to_major(hyperedge_id);
93+
return this->_incident_with_major(hyperedge_id);
9494
else
95-
return this->_incident_to_minor(hyperedge_id);
95+
return this->_incident_with_minor(hyperedge_id);
9696
}
9797

9898
[[nodiscard]] gl_attr_force_inline types::size_type hyperedge_size(
@@ -155,12 +155,12 @@ class incidence_list<hgl::undirected_t, LayoutTag> final {
155155
}
156156
}
157157

158-
[[nodiscard]] gl_attr_force_inline auto _incident_to_major(const types::id_type major_id
158+
[[nodiscard]] gl_attr_force_inline auto _incident_with_major(const types::id_type major_id
159159
) const noexcept {
160160
return std::views::all(this->_major_storage[major_id]);
161161
}
162162

163-
[[nodiscard]] gl_attr_force_inline auto _incident_to_minor(const types::id_type minor_id
163+
[[nodiscard]] gl_attr_force_inline auto _incident_with_minor(const types::id_type minor_id
164164
) const noexcept {
165165
return std::views::iota(0uz, this->_major_storage.size())
166166
| std::views::filter([this, minor_id](types::id_type major_id) {

include/hgl/impl/incidence_matrix.hpp

Lines changed: 207 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <algorithm>
1212
#include <ranges>
1313
#include <vector>
14+
#include <cstdint>
1415

1516
#ifdef HGL_TESTING
1617
namespace 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

Comments
 (0)