libsemigroups  v3.2.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
node-manager.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2019-2025 James D. Mitchell
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18
19// This file contains the declaration for a class to manage nodes for
20// NodeManagedGraph instances.
21
22#ifndef LIBSEMIGROUPS_DETAIL_NODE_MANAGER_HPP_
23#define LIBSEMIGROUPS_DETAIL_NODE_MANAGER_HPP_
24
25#include <cstddef> // for size_t
26#include <cstdint> // for uint32_t
27#include <numeric> // for iota
28#include <type_traits> // for true_type
29#include <vector> // for vector
30
31#include "libsemigroups/config.hpp" // for LIBSEMIGROUPS_DEBUG
32#include "libsemigroups/constants.hpp" // for UNDEFINED
33#include "libsemigroups/debug.hpp" // for LIBSEMIGROUPS_ASSERT/DEBUG
34#include "libsemigroups/exception.hpp" // for LISEMIGROUPS_EXCEPTION
35#include "libsemigroups/ranges.hpp"
36
37namespace libsemigroups {
38 namespace detail {
39 template <typename Node>
40 class NodeManager {
41 public:
43 // NodeManager - typedefs - public
45
46 using node_type = Node;
47 using Perm = std::vector<node_type>;
48
50 // NodeManager - data - protected
52 protected:
53 node_type _current;
54 node_type _current_la;
55
57 // NodeManager - data - private
59 private:
60 static constexpr node_type _id_node = 0;
61
62 std::vector<node_type> _bckwd;
63 node_type _first_free_node;
64 std::vector<node_type> _forwd;
65 float _growth_factor;
66 mutable std::vector<node_type> _ident;
67 node_type _last_active_node;
68
69 struct Stats {
70 std::atomic_uint64_t num_nodes_active;
71 std::atomic_uint64_t num_nodes_defined;
72 std::atomic_uint64_t num_nodes_killed;
73
74 Stats()
75 : num_nodes_active(1), num_nodes_defined(1), num_nodes_killed(0) {}
76
77 Stats(Stats const& that)
78 : num_nodes_active(that.num_nodes_active.load()),
79 num_nodes_defined(that.num_nodes_defined.load()),
80 num_nodes_killed(that.num_nodes_killed.load()) {}
81
82 Stats(Stats&& that)
83 : num_nodes_active(that.num_nodes_active.load()),
84 num_nodes_defined(that.num_nodes_defined.load()),
85 num_nodes_killed(that.num_nodes_killed.load()) {}
86
87 Stats& operator=(Stats const& that) {
88 num_nodes_active = that.num_nodes_active.load();
89 num_nodes_defined = that.num_nodes_defined.load();
90 num_nodes_killed = that.num_nodes_killed.load();
91 return *this;
92 }
93
94 Stats& operator=(Stats&& that) {
95 num_nodes_active = that.num_nodes_active.load();
96 num_nodes_defined = that.num_nodes_defined.load();
97 num_nodes_killed = that.num_nodes_killed.load();
98 return *this;
99 }
100 } _stats;
101
102 public:
104 // NodeManager - constructors + destructor - public
106
107 NodeManager();
108
109 NodeManager(NodeManager const& that);
110 NodeManager(NodeManager&&) = default;
111
112 NodeManager& operator=(NodeManager const& that);
113 NodeManager& operator=(NodeManager&&) = default;
114
115 ~NodeManager();
116
118 // NodeManager - member functions - public
120
121 node_type& cursor() {
122 return _current;
123 }
124
125 node_type& lookahead_cursor() {
126 return _current_la;
127 }
128
129 node_type const& lookahead_cursor() const {
130 return _current_la;
131 }
132
133 // std::vector::size is noexcept
134 inline size_t node_capacity() const noexcept {
135 return _forwd.size();
136 }
137
138 inline node_type first_free_node() const noexcept {
139 return _first_free_node;
140 }
141
142 inline bool has_free_nodes() const noexcept {
143 return _first_free_node != UNDEFINED;
144 }
145
146 // not noexcept since std::vector::operator[] isn't.
147 inline bool is_active_node(node_type c) const {
148 LIBSEMIGROUPS_ASSERT(c < _ident.size() || c == UNDEFINED);
149 return c != UNDEFINED && _ident[c] == c;
150 }
151
152 [[nodiscard]] size_t position_of_node(node_type n) const;
153
154 inline bool is_valid_node(node_type c) const noexcept {
155 return c < _forwd.size();
156 }
157
158 // not noexcept since std::vector::operator[] isn't.
159 inline node_type next_active_node(node_type c) const {
160 return _forwd[c];
161 }
162
163 // Note that these iterators are invalidated by any changes to the
164 // container, i.e. they can't be used as a substitute for cursors.
165 auto cbegin_active_nodes() const {
166 return rx::begin(ActiveNodesRange(this));
167 }
168
169 // Note that these iterators are invalidated by any changes to the
170 // container, i.e. they can't be used as a substitute for cursors.
171 auto cend_active_nodes() const {
172 return rx::end(ActiveNodesRange(this));
173 }
174
175 inline uint64_t number_of_nodes_active() const noexcept {
176 return _stats.num_nodes_active;
177 }
178
179 inline uint64_t number_of_nodes_defined() const noexcept {
180 return _stats.num_nodes_defined;
181 }
182
183 inline uint64_t number_of_nodes_killed() const noexcept {
184 return _stats.num_nodes_killed;
185 }
186
187 NodeManager& growth_factor(float val);
188
189 float growth_factor() const noexcept {
190 return _growth_factor;
191 }
192
194 // NodeManager - member functions - protected
196
197 // not noexcept because free_node isn't, and std::vector::operator[]
198 // isn't.
199
200 inline void union_nodes(node_type min, node_type max) {
201 LIBSEMIGROUPS_ASSERT(is_active_node(min));
202 LIBSEMIGROUPS_ASSERT(is_active_node(max));
203 LIBSEMIGROUPS_ASSERT(max > min);
204 free_node(max);
205 // Leave a "forwarding address" so we know what <max> was identified
206 // with
207 _ident[max] = min;
208 }
209
210 // not noexcept since std::vector::operator[] isn't.
211
212 inline node_type find_node(node_type c) const {
213 LIBSEMIGROUPS_ASSERT(is_valid_node(c));
214 while (true) {
215 node_type d = _ident[c];
216 if (d == c) {
217 return d;
218 }
219 node_type e = _ident[d];
220 if (d == e) {
221 return d;
222 }
223 _ident[c] = e;
224 c = e;
225 }
226 LIBSEMIGROUPS_ASSERT(is_active_node(c));
227 return c;
228 }
229
230 void add_active_nodes(size_t);
231 void add_free_nodes(size_t);
232 void erase_free_nodes();
233 node_type new_active_node();
234 // TODO rename -> swap_nodes_no_checks
235 void switch_nodes(node_type const, node_type const);
236 // TODO rename -> permute_nodes_no_checks
237 void apply_permutation(Perm p);
238
239 void clear();
240 void compact();
241
242 // not noexcept since std::vector::operator[] isn't.
243 void free_node(node_type const);
244
246 // NodeManager - data - protected
248
249 constexpr node_type initial_node() const noexcept {
250 return _id_node;
251 }
252
253 private:
254 void compact(size_t N);
255
256 struct ActiveNodesRange {
257 using output_type = node_type;
258
259 NodeManager const* _node_manager;
260 output_type _current;
261
262 ActiveNodesRange() : _node_manager(nullptr), _current(UNDEFINED) {}
263
264 explicit ActiveNodesRange(NodeManager const* nm)
265 : _node_manager(nm), _current(nm->initial_node()) {}
266
267 output_type get() const noexcept {
268 return _current;
269 }
270
271 void next() noexcept {
272 _current = _node_manager->next_active_node(_current);
273 }
274
275 bool at_end() const noexcept {
276 return _node_manager == nullptr
277 || _current == _node_manager->first_free_node();
278 }
279
280 size_t size_hint() const noexcept {
281 return _node_manager->number_of_nodes_active();
282 }
283
284 static constexpr bool is_finite = true;
285 static constexpr bool is_idempotent = true;
286 };
287
288 public:
289 ActiveNodesRange active_nodes() const {
290 return ActiveNodesRange(this);
291 }
292
293#ifdef LIBSEMIGROUPS_DEBUG
294
295 protected:
297 // NodeManager - member functions (debug only) - protected
299 void debug_validate_forwd_bckwd() const;
300#endif
301 };
302
303 } // namespace detail
304} // namespace libsemigroups
305
306#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
307// TODO replace uint32_t by Node
308template <>
309struct rx::is_input_range<
310 typename libsemigroups::detail::NodeManager<uint32_t>::ActiveNodesRange>
311 : std::true_type {};
312#endif
313#include "node-manager.tpp"
314
315#endif // LIBSEMIGROUPS_DETAIL_NODE_MANAGER_HPP_
Undefined const UNDEFINED
Value for something undefined.
T max(T... args)
T min(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44