Skip to content

Commit 62968e1

Browse files
committed
layout-based incidence matrix definition
1 parent d105f23 commit 62968e1

2 files changed

Lines changed: 431 additions & 74 deletions

File tree

include/hgl/impl/incidence_matrix.hpp

Lines changed: 106 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#pragma once
66

77
#include "hgl/types/types.hpp"
8+
#include "layout_tags.hpp"
89

910
#include <algorithm>
1011
#include <ranges>
@@ -18,8 +19,12 @@ struct test_incidence_matrix;
1819

1920
namespace hgl::impl {
2021

22+
template <type_traits::c_hypergraph_layout_tag LayoutTag>
2123
class undirected_incidence_matrix final {
2224
public:
25+
using layout_tag = LayoutTag;
26+
27+
// Rows are "Major", Columns are "Minor"
2328
using matrix_row_type = std::vector<bool>;
2429
using hypergraph_storage_type = std::vector<matrix_row_type>;
2530

@@ -31,10 +36,10 @@ class undirected_incidence_matrix final {
3136
undirected_incidence_matrix(
3237
const types::size_type n_vertices, const types::size_type n_hyperedges
3338
)
34-
: _matrix_row_size{n_hyperedges}, _matrix{n_vertices} {
35-
for (auto& row : this->_matrix)
36-
row.resize(this->_matrix_row_size, false);
37-
}
39+
: _minor_size{layout_tag::minor(n_vertices, n_hyperedges)},
40+
_major_storage(
41+
layout_tag::major(n_vertices, n_hyperedges), matrix_row_type(_minor_size, false)
42+
) {}
3843

3944
undirected_incidence_matrix(undirected_incidence_matrix&&) = default;
4045
undirected_incidence_matrix& operator=(undirected_incidence_matrix&&) = default;
@@ -44,89 +49,151 @@ class undirected_incidence_matrix final {
4449
// --- vertex methods ---
4550

4651
gl_attr_force_inline void add_vertices(const types::size_type n) noexcept {
47-
this->_matrix.resize(
48-
this->_matrix.size() + n, matrix_row_type(this->_matrix_row_size, false)
49-
);
52+
if constexpr (std::same_as<layout_tag, impl::vertex_major_t>)
53+
this->_add_major(n);
54+
else
55+
this->_add_minor(n);
5056
}
5157

5258
gl_attr_force_inline void remove_vertex(const types::id_type vertex_id) noexcept {
53-
this->_matrix.erase(this->_matrix.begin() + vertex_id);
59+
if constexpr (std::same_as<layout_tag, impl::vertex_major_t>)
60+
this->_remove_major(vertex_id);
61+
else
62+
this->_remove_minor(vertex_id);
5463
}
5564

5665
[[nodiscard]] gl_attr_force_inline auto incident_hyperedges(const types::id_type vertex_id
5766
) const noexcept {
58-
return std::views::iota(0uz, this->_matrix_row_size)
59-
| std::views::filter(
60-
[&vertex_row = this->_matrix[vertex_id]](const auto hyperedge_id) -> bool {
61-
return vertex_row[hyperedge_id];
62-
}
63-
);
67+
if constexpr (std::same_as<layout_tag, impl::vertex_major_t>)
68+
return this->_incident_to_major(vertex_id);
69+
else
70+
return this->_incident_to_minor(vertex_id);
6471
}
6572

6673
[[nodiscard]] types::size_type degree(const types::id_type vertex_id) const noexcept {
67-
types::size_type deg = 0;
68-
for (const bool is_hyperedge_incident : this->_matrix[vertex_id])
69-
deg += static_cast<types::size_type>(is_hyperedge_incident);
70-
return deg;
74+
if constexpr (std::same_as<layout_tag, impl::vertex_major_t>)
75+
return this->_count_major_bits(vertex_id);
76+
else
77+
return this->_count_minor_bits(vertex_id);
7178
}
7279

7380
// --- hyperedge methods ---
7481

75-
void add_hyperedges(const types::size_type n) noexcept {
76-
this->_matrix_row_size += n;
77-
for (auto& row : this->_matrix)
78-
row.resize(this->_matrix_row_size, false);
82+
gl_attr_force_inline void add_hyperedges(const types::size_type n) noexcept {
83+
if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t>)
84+
this->_add_major(n);
85+
else
86+
this->_add_minor(n);
7987
}
8088

81-
void remove_hyperedge(const types::id_type hyperedge_id) noexcept {
82-
this->_matrix_row_size--;
83-
for (auto& row : this->_matrix)
84-
row.erase(row.begin() + hyperedge_id);
89+
gl_attr_force_inline void remove_hyperedge(const types::id_type hyperedge_id) noexcept {
90+
if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t>)
91+
this->_remove_major(hyperedge_id);
92+
else
93+
this->_remove_minor(hyperedge_id);
8594
}
8695

8796
[[nodiscard]] gl_attr_force_inline auto incident_vertices(const types::id_type hyperedge_id
8897
) const noexcept {
89-
return std::views::iota(0uz, this->_matrix.size())
90-
| std::views::filter([this, hyperedge_id](const auto vertex_id) {
91-
return this->_matrix[vertex_id][hyperedge_id];
92-
});
98+
if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t>)
99+
return this->_incident_to_major(hyperedge_id);
100+
else
101+
return this->_incident_to_minor(hyperedge_id);
93102
}
94103

95104
[[nodiscard]] types::size_type hyperedge_size(const types::id_type hyperedge_id
96105
) const noexcept {
97-
types::size_type size = 0;
98-
for (const auto& row : this->_matrix)
99-
size += static_cast<types::size_type>(row[hyperedge_id]);
100-
return size;
106+
if constexpr (std::same_as<layout_tag, impl::hyperedge_major_t>)
107+
return this->_count_major_bits(hyperedge_id);
108+
else
109+
return this->_count_minor_bits(hyperedge_id);
101110
}
102111

103112
// --- binding methods ---
104113

105114
gl_attr_force_inline void bind(
106115
const types::id_type vertex_id, const types::id_type hyperedge_id
107116
) noexcept {
108-
this->_matrix[vertex_id][hyperedge_id] = true;
117+
const auto [major_id, minor_id] = layout_tag::majmin(vertex_id, hyperedge_id);
118+
this->_major_storage[major_id][minor_id] = true;
109119
}
110120

111121
gl_attr_force_inline void unbind(
112122
const types::id_type vertex_id, const types::id_type hyperedge_id
113123
) noexcept {
114-
this->_matrix[vertex_id][hyperedge_id] = false;
124+
const auto [major_id, minor_id] = layout_tag::majmin(vertex_id, hyperedge_id);
125+
this->_major_storage[major_id][minor_id] = false;
115126
}
116127

117128
[[nodiscard]] gl_attr_force_inline bool are_bound(
118129
const types::id_type vertex_id, const types::id_type hyperedge_id
119130
) const noexcept {
120-
return this->_matrix[vertex_id][hyperedge_id];
131+
const auto [major_id, minor_id] = layout_tag::majmin(vertex_id, hyperedge_id);
132+
return this->_major_storage[major_id][minor_id];
121133
}
122134

123135
#ifdef HGL_TESTING
124136
friend struct hgl_testing::test_incidence_matrix;
125137
#endif
126138

127139
private:
128-
types::size_type _matrix_row_size = 0uz;
129-
hypergraph_storage_type _matrix;
140+
types::size_type _minor_size = 0uz; // matrix row size
141+
hypergraph_storage_type _major_storage;
142+
143+
gl_attr_force_inline void _add_major(const types::size_type n) noexcept {
144+
this->_major_storage.resize(
145+
this->_major_storage.size() + n, matrix_row_type(this->_minor_size, false)
146+
);
147+
}
148+
149+
void _add_minor(const types::size_type n) noexcept {
150+
this->_minor_size += n;
151+
for (auto& row : this->_major_storage)
152+
row.resize(this->_minor_size, false);
153+
}
154+
155+
gl_attr_force_inline void _remove_major(const types::id_type major_id) noexcept {
156+
this->_major_storage.erase(this->_major_storage.begin() + major_id);
157+
}
158+
159+
gl_attr_force_inline void _remove_minor(const types::id_type minor_id) noexcept {
160+
if (this->_minor_size == 0)
161+
return;
162+
this->_minor_size--;
163+
for (auto& row : this->_major_storage) {
164+
row.erase(row.begin() + minor_id);
165+
}
166+
}
167+
168+
[[nodiscard]] auto _incident_to_major(const types::id_type major_id) const noexcept {
169+
return std::views::iota(0uz, this->_minor_size)
170+
| std::views::filter(
171+
[&row = this->_major_storage[major_id]](const types::id_type minor_id) {
172+
return row[minor_id];
173+
}
174+
);
175+
}
176+
177+
[[nodiscard]] auto _incident_to_minor(const types::id_type minor_id) const noexcept {
178+
return std::views::iota(0uz, this->_major_storage.size())
179+
| std::views::filter([this, minor_id](const types::id_type major_id) {
180+
return this->_major_storage[major_id][minor_id];
181+
});
182+
}
183+
184+
[[nodiscard]] types::size_type _count_major_bits(const types::id_type major_id) const noexcept {
185+
types::size_type count = 0;
186+
for (const bool bit : this->_major_storage[major_id])
187+
count += static_cast<types::size_type>(bit);
188+
return count;
189+
}
190+
191+
[[nodiscard]] types::size_type _count_minor_bits(const types::id_type minor_id) const noexcept {
192+
types::size_type count = 0;
193+
for (const auto& row : this->_major_storage)
194+
count += static_cast<types::size_type>(row[minor_id]);
195+
return count;
196+
}
130197
};
131198

132199
} // namespace hgl::impl

0 commit comments

Comments
 (0)