mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
AdjacencyMatrix.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <array>
5
6
7namespace m {
8
10struct M_EXPORT AdjacencyMatrix
11{
13 template<bool C>
14 struct Proxy
15 {
16 friend struct AdjacencyMatrix;
17
18 static constexpr bool Is_Const = C;
19
20 private:
21 using reference_type = std::conditional_t<Is_Const, const AdjacencyMatrix&, AdjacencyMatrix&>;
22
24 std::size_t i_;
25 std::size_t j_;
26
27 Proxy(reference_type M, std::size_t i, std::size_t j) : M_(M) , i_(i), j_(j) {
28 M_insist(i < M_.num_vertices_);
29 M_insist(j < M_.num_vertices_);
30 }
31 Proxy(Proxy&&) = default;
32
33 public:
34 operator bool() const { return M_.m_[i_][j_]; }
35
36 template<bool C_ = Is_Const>
37 requires (not C_)
38 Proxy & operator=(bool val) { M_.m_[i_][j_] = val; return *this; }
39
40 Proxy & operator=(const Proxy<false> &other) {
41 static_assert(not C);
42 return operator=(bool(other));
43 }
44
45 Proxy & operator=(const Proxy<true> &other) {
46 static_assert(not C);
47 return operator=(bool(other));
48 }
49
51 static_assert(not C);
52 return operator=(bool(other));
53 }
55 static_assert(not C);
56 return operator=(bool(other));
57 }
58 };
59
60 private:
61 std::array<SmallBitset, SmallBitset::CAPACITY> m_;
62 std::size_t num_vertices_ = 0;
63
64 public:
66 AdjacencyMatrix(std::size_t num_vertices) : num_vertices_(num_vertices) { }
67
68 explicit AdjacencyMatrix(const AdjacencyMatrix&) = default;
70
72
74 Proxy<true> operator()(std::size_t i, std::size_t j) const { return Proxy<true>(*this, i, j); }
75
77 Proxy<false> operator()(std::size_t i, std::size_t j) { return Proxy<false>(*this, i, j); }
78
79 Proxy<true> at(std::size_t i, std::size_t j) const {
80 if (i >= num_vertices_ or j >= num_vertices_)
81 throw out_of_range("index is out of bounds");
82 return operator()(i, j);
83 }
84
85 Proxy<false> at(std::size_t i, std::size_t j) {
86 if (i >= num_vertices_ or j >= num_vertices_)
87 throw out_of_range("index is out of bounds");
88 return operator()(i, j);
89 }
90
93 SmallBitset R_old(0);
94 SmallBitset R_new(src);
95 for (;;) {
96 auto R = R_new - R_old;
97 if (R.empty()) goto exit;
98 R_old = R_new;
99 for (auto x : R)
100 R_new |= m_[x]; // add all nodes reachable from node `x` to the set of reachable nodes
101 }
102exit:
103 return R_new;
104 }
105
109 SmallBitset R_old(0);
110 SmallBitset R_new(src & S);
111 for (;;) {
112 auto R = R_new - R_old;
113 if (R.empty()) goto exit;
114 R_old = R_new;
115 for (auto x : R)
116 R_new |= m_[x] & S; // add all nodes in `S` reachable from node `x` to the set of reachable nodes
117 }
118exit:
119 return R_new;
120 }
121
124 SmallBitset neighbors;
125 for (auto it : S)
126 neighbors |= m_[it];
127 return neighbors - S;
128 }
129
133 bool is_connected(SmallBitset S) const { return reachable(S.begin().as_set(), S) == S; }
134
136 bool is_connected(SmallBitset left, SmallBitset right) const {
137 SmallBitset neighbors;
138 /* Compute the neighbors of `right`. */
139 for (auto it : right)
140 neighbors = neighbors | m_[it];
141 /* Intersect `left` with the neighbors of `right`. If the result is non-empty, `left` and `right` are
142 * immediately connected by a join. */
143 return not (left & neighbors).empty();
144 }
145
149 AdjacencyMatrix transitive_closure_directed() const;
150
154 AdjacencyMatrix transitive_closure_undirected() const;
155
158 void for_each_CSG_undirected(SmallBitset super, SmallBitset source, std::function<void(SmallBitset)> callback) const
159 {
160 source = source & super; // restrict sources to vertices in `super`
161
162 std::deque<std::pair<SmallBitset, SmallBitset>> Q;
163 for (auto it = source.begin(); it != source.end(); ++it) {
164 const SmallBitset I = it.as_set();
166 Q.emplace_back(I, source & ~I.mask_to_lo()); // exclude larger sources
167
168 while (not Q.empty()) {
169 auto [S, X_old] = Q.front();
170 Q.pop_front();
171
172 callback(S);
173
174 const SmallBitset N = (neighbors(S) & super) - X_old;
175 const SmallBitset X_new = X_old | N;
176 for (SmallBitset n = least_subset(N); bool(n); n = next_subset(n, N)) // enumerate 2^{neighbors of S}
177 Q.emplace_back(S | n, X_new);
178 }
179 }
180 }
181
184 void for_each_CSG_undirected(SmallBitset super, std::function<void(SmallBitset)> callback) const {
185 for_each_CSG_undirected(super, super, std::move(callback));
186 }
187
190 void for_each_CSG_pair_undirected(SmallBitset super, std::function<void(SmallBitset, SmallBitset)> callback) const {
191 auto callback_CSG = [this, super, &callback](SmallBitset first) {
192 auto callback_partial = [&callback, first](SmallBitset second) {
193 callback(first, second);
194 };
195 const SmallBitset N_first = neighbors(first) & super;
196 const SmallBitset super_second = (super - first) & first.hi().mask_to_lo();
197 for_each_CSG_undirected(super_second, N_first, callback_partial);
198 };
199 for_each_CSG_undirected(super, callback_CSG);
200 }
201
204 AdjacencyMatrix minimum_spanning_forest(std::function<double(std::size_t, std::size_t)> weight) const;
205
208 AdjacencyMatrix tree_directed_away_from(SmallBitset root);
209
211 bool operator==(const AdjacencyMatrix &other) const {
212 if (this->num_vertices_ != other.num_vertices_) return false;
213 for (std::size_t i = 0; i != num_vertices_; ++i) {
214 if (this->m_[i] != other.m_[i])
215 return false;
216 }
217 return true;
218 }
219 bool operator!=(const AdjacencyMatrix &other) const { return not operator==(other); }
220
222 friend std::ostream & operator<<(std::ostream &out, const AdjacencyMatrix &M) {
224 return out;
225 }
226
227 friend std::string to_string(const AdjacencyMatrix &M) {
228 std::ostringstream oss;
229 oss << M;
230 return oss.str();
231 }
232
233 void print_fixed_length(std::ostream &out, unsigned length) const {
234 M_insist(length <= SmallBitset::CAPACITY);
235 out << "Adjacency Matrix";
236 for (unsigned i = 0; i != length; ++i) {
237 out << '\n';
238 m_[i].print_fixed_length(out, length);
239 }
240 }
241
242 void dump(std::ostream &out) const;
243 void dump() const;
245};
246
247}
#define M_insist(...)
Definition: macro.hpp:129
‍mutable namespace
Definition: Backend.hpp:10
SmallBitset least_subset(SmallBitset S)
Returns the least subset of a given set, i.e. the set represented by the lowest 1 bit.
Definition: ADT.hpp:267
SmallBitset next_subset(SmallBitset subset, SmallBitset set)
Returns the next subset of a given subset and `set.
Definition: ADT.hpp:270
A proxy to access single entries in the AdjacencyMatrix.
Proxy(reference_type M, std::size_t i, std::size_t j)
Proxy & operator=(const Proxy< false > &other)
Proxy & operator=(Proxy< true > &&other)
std::conditional_t< Is_Const, const AdjacencyMatrix &, AdjacencyMatrix & > reference_type
Proxy & operator=(const Proxy< true > &other)
Proxy & operator=(Proxy< false > &&other)
Proxy(Proxy &&)=default
An adjacency matrix for a given query graph.
Proxy< false > operator()(std::size_t i, std::size_t j)
Returns the bit at position (i, j).
friend std::string to_string(const AdjacencyMatrix &M)
bool is_connected(SmallBitset left, SmallBitset right) const
Returns true iff there is at least one edge (join) between left and right.
bool operator!=(const AdjacencyMatrix &other) const
SmallBitset reachable(SmallBitset src) const
Computes the set of nodes reachable from src, i.e. the set of nodes reachable from any node in src.
void for_each_CSG_pair_undirected(SmallBitset super, std::function< void(SmallBitset, SmallBitset)> callback) const
Enumerate all pairs of connected subgraphs (CSGs) that are connected by at least one edge.
SmallBitset reachable(SmallBitset src, SmallBitset S) const
Computes the set of nodes in S reachable from src, i.e. the set of nodes in S reachable from any node...
Proxy< true > operator()(std::size_t i, std::size_t j) const
Returns the bit at position (i, j).
std::array< SmallBitset, SmallBitset::CAPACITY > m_
matrix entries
AdjacencyMatrix & operator=(AdjacencyMatrix &&)=default
M_LCOV_EXCL_START friend std::ostream & operator<<(std::ostream &out, const AdjacencyMatrix &M)
AdjacencyMatrix(std::size_t num_vertices)
std::size_t num_vertices_
number of sources of the QueryGraph represented by this matrix
bool is_connected(SmallBitset S) const
Returns true iff the subproblem S is connected.
Proxy< false > at(std::size_t i, std::size_t j)
bool operator==(const AdjacencyMatrix &other) const
Compares two AdjacencyMatrixs element-wise.
Proxy< true > at(std::size_t i, std::size_t j) const
void for_each_CSG_undirected(SmallBitset super, std::function< void(SmallBitset)> callback) const
Enumerate all connected subgraphs (CSGs) of the graph induced by vertex super set super.
AdjacencyMatrix(const AdjacencyMatrix &)=default
SmallBitset neighbors(SmallBitset S) const
Computes the neighbors of S.
AdjacencyMatrix(AdjacencyMatrix &&)=default
void print_fixed_length(std::ostream &out, unsigned length) const
void for_each_CSG_undirected(SmallBitset super, SmallBitset source, std::function< void(SmallBitset)> callback) const
Enumerate all connected subgraphs (CSGs) of the graph induced by vertex super set super,...
Implements a small and efficient set over integers in the range of 0 to 63 (including).
Definition: ADT.hpp:26
bool is_singleton() const
Definition: ADT.hpp:165
SmallBitset hi() const
Returns the highest set bit as a SmallBitset.
Definition: ADT.hpp:168
SmallBitset mask_to_lo() const
Returns a mask up to and including the lowest set bit.
Definition: ADT.hpp:197
bool empty() const
Returns true if there are no elements in this SmallBitset.
Definition: ADT.hpp:163
auto end() const
Definition: ADT.hpp:175
auto begin() const
Definition: ADT.hpp:173
Signals that an index-based or key-based access was out of range.
Definition: exception.hpp:43