libsemigroups  v3.0.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// ToddCoxeterDigraph 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 NodeType>
40 class NodeManager {
41 public:
43 // NodeManager - typedefs - public
45
47 using node_type = NodeType;
48 using Perm = std::vector<node_type>;
49
51 // NodeManager - constructors + destructor - public
53
54 NodeManager();
55
56 NodeManager(NodeManager const&) = default;
57 NodeManager(NodeManager&&) = default;
58
59 NodeManager& operator=(NodeManager const&) = default;
60 NodeManager& operator=(NodeManager&&) = default;
61
62 ~NodeManager();
63
65 // NodeManager - member functions - public
67
68 node_type& cursor() {
69 return _current;
70 }
71
72 node_type& lookahead_cursor() {
73 return _current_la;
74 }
75
88 // std::vector::size is noexcept
89 inline size_t node_capacity() const noexcept {
90 return _forwd.size();
91 }
92
105 inline node_type first_free_node() const noexcept {
106 return _first_free_node;
107 }
108
121 inline bool has_free_nodes() const noexcept {
122 return _first_free_node != UNDEFINED;
123 }
124
136 // not noexcept since std::vector::operator[] isn't.
137 inline bool is_active_node(node_type c) const {
138 LIBSEMIGROUPS_ASSERT(c < _ident.size() || c == UNDEFINED);
139 return c != UNDEFINED && _ident[c] == c;
140 }
141
153 inline bool is_valid_node(node_type c) const noexcept {
154 return c < _forwd.size();
155 }
156
168 // not noexcept since std::vector::operator[] isn't.
169 inline node_type next_active_node(node_type c) const {
170 LIBSEMIGROUPS_ASSERT(is_active_node(c));
171 return _forwd[c];
172 }
173
174 // Note that these iterators are invalidated by any changes to the
175 // container, i.e. they can't be used as a substitute for cursors.
176 auto cbegin_active_nodes() const {
177 return rx::begin(ActiveNodesRange(this));
178 }
179
180 // Note that these iterators are invalidated by any changes to the
181 // container, i.e. they can't be used as a substitute for cursors.
182 auto cend_active_nodes() const {
183 return rx::end(ActiveNodesRange(this));
184 }
185
198 inline size_t number_of_nodes_active() const noexcept {
199 return _active;
200 }
201
214 inline size_t number_of_nodes_defined() const noexcept {
215 return _defined;
216 }
217
230 inline size_t number_of_nodes_killed() const noexcept {
231 return _nodes_killed;
232 }
233
249 NodeManager& growth_factor(float val);
250
260 float growth_factor() const noexcept {
261 return _growth_factor;
262 }
263
265 // NodeManager - member functions - protected
267
268 // not noexcept because free_node isn't, and std::vector::operator[]
269 // isn't.
270
271 inline void union_nodes(node_type min, node_type max) {
272 LIBSEMIGROUPS_ASSERT(is_active_node(min));
273 LIBSEMIGROUPS_ASSERT(is_active_node(max));
274 LIBSEMIGROUPS_ASSERT(max > min);
275 free_node(max);
276 // Leave a "forwarding address" so we know what <max> was identified
277 // with
278 _ident[max] = min;
279 }
280
281 // not noexcept since std::vector::operator[] isn't.
282
283 inline node_type find_node(node_type c) const {
284 LIBSEMIGROUPS_ASSERT(is_valid_node(c));
285 while (true) {
286 node_type d = _ident[c];
287 if (d == c) {
288 return d;
289 }
290 node_type e = _ident[d];
291 if (d == e) {
292 return d;
293 }
294 _ident[c] = e;
295 c = e;
296 }
297 LIBSEMIGROUPS_ASSERT(is_active_node(c));
298 return c;
299 }
300
301 void add_active_nodes(size_t);
302 void add_free_nodes(size_t);
303 void erase_free_nodes();
304 node_type new_active_node();
305 // TODO rename -> swap_nodes_no_checks
306 void switch_nodes(node_type const, node_type const);
307 // TODO rename -> permute_nodes_no_checks
308 void apply_permutation(Perm p);
309
310 // not noexcept since std::vector::operator[] isn't.
311 void free_node(node_type const);
312
313 void clear();
314
316 // NodeManager - data - protected
318
319 constexpr node_type initial_node() const noexcept {
320 return _id_node;
321 }
322
323 static constexpr node_type _id_node = 0;
324 node_type _current;
325 node_type _current_la;
326
327 private:
328 struct ActiveNodesRange {
329 using output_type = node_type;
330
331 NodeManager const* _node_manager;
332 output_type _current;
333
334 ActiveNodesRange() : _node_manager(nullptr), _current(UNDEFINED) {}
335
336 explicit ActiveNodesRange(NodeManager const* nm)
337 : _node_manager(nm), _current(nm->initial_node()) {}
338
339 output_type get() const noexcept {
340 return _current;
341 }
342
343 void next() noexcept {
344 _current = _node_manager->next_active_node(_current);
345 }
346
347 bool at_end() const noexcept {
348 return _node_manager == nullptr
349 || _current == _node_manager->first_free_node();
350 }
351
352 size_t size_hint() const noexcept {
353 return _node_manager->number_of_nodes_active();
354 }
355
356 static constexpr bool is_finite = true;
357 static constexpr bool is_idempotent = true;
358 };
359
360 public:
361 ActiveNodesRange active_nodes() const {
362 return ActiveNodesRange(this);
363 }
364
365 private:
367 // NodeManager - member functions - private
369
371 // NodeManager - data - private
373
374 // Stats
375 size_t _active;
376 size_t _defined;
377 size_t _nodes_killed;
378
379 // Settings
380 float _growth_factor;
381
382 // Data
383 std::vector<node_type> _bckwd;
384 node_type _first_free_node;
385 std::vector<node_type> _forwd;
386 mutable std::vector<node_type> _ident;
387 node_type _last_active_node;
388
389#ifdef LIBSEMIGROUPS_DEBUG
390
391 protected:
393 // NodeManager - member functions (debug only) - protected
395 void debug_validate_forwd_bckwd() const;
396#endif
397 };
398
399 } // namespace detail
400} // namespace libsemigroups
401
402#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
403// TODO replace uint32_t by Node
404template <>
405struct rx::is_input_range<
406 typename libsemigroups::detail::NodeManager<uint32_t>::ActiveNodesRange>
407 : std::true_type {};
408#endif
409#include "node-manager.tpp"
410
411#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