1#ifndef LIBTEDDY_DETAILS_NODE_MANAGER_HPP
2#define LIBTEDDY_DETAILS_NODE_MANAGER_HPP
4#include <libteddy/details/config.hpp>
5#include <libteddy/details/debug.hpp>
6#include <libteddy/details/hash_tables.hpp>
7#include <libteddy/details/node.hpp>
8#include <libteddy/details/node_pool.hpp>
9#include <libteddy/details/operators.hpp>
10#include <libteddy/details/tools.hpp>
11#include <libteddy/details/types.hpp>
29 static constexpr int32 value = 1;
31 std::vector<int32> domains_;
33 mixed(std::vector<int32> domains) :
34 domains_(
static_cast<std::vector<int32>&&
>(domains)) {};
36 auto operator[] (int32
const index)
const
38 return domains_[as_uindex(index)];
47 static constexpr int32 value = N;
49 constexpr auto operator[] ([[maybe_unused]] int32
const index)
const
58 static constexpr bool value =
false;
64 static constexpr bool value =
true;
70 static constexpr bool value =
false;
76 static constexpr bool value =
true;
80template<
class Data,
class Degree,
class Domain>
85 using son_container =
typename node_t::son_container;
95 int64 extraNodePoolSize,
96 std::vector<int32> order
103 int64 extraNodePoolSize,
104 std::vector<int32> order,
115 auto set_cache_ratio (
double ratio) ->
void;
116 auto set_gc_ratio (
double ratio) ->
void;
117 auto set_auto_reorder (
bool doReorder) ->
void;
124 int64 extraNodePoolSize,
125 std::vector<int32> order,
130 [[nodiscard]] auto get_terminal_node (int32 value) const ->
node_t*;
131 [[nodiscard]] auto make_terminal_node (int32 value) ->
node_t*;
132 [[nodiscard]] auto make_internal_node (
134 son_container const& sons
136 [[nodiscard]] auto make_son_container (int32 domain) -> son_container;
137 [[nodiscard]] auto get_level (int32 index) const -> int32;
138 [[nodiscard]] auto get_level (
node_t*
node) const -> int32;
139 [[nodiscard]] auto get_leaf_level () const -> int32;
140 [[nodiscard]] auto get_index (int32 level) const -> int32;
141 [[nodiscard]] auto get_domain (int32 index) const -> int32;
142 [[nodiscard]] auto get_domain (
node_t*
node) const -> int32;
143 [[nodiscard]] auto get_node_count (int32 index) const -> int64;
144 [[nodiscard]] auto get_node_count (
node_t*
node) const -> int64;
145 [[nodiscard]] auto get_node_count () const -> int64;
146 [[nodiscard]] auto get_var_count () const -> int32;
147 [[nodiscard]] auto get_order () const -> std::vector<int32> const&;
148 [[nodiscard]] auto get_domains () const -> std::vector<int32>;
149 auto force_gc () ->
void;
151 auto to_dot_graph (std::ostream& ost) const ->
void;
152 auto to_dot_graph (std::ostream& ost,
node_t*
node) const ->
void;
154 [[nodiscard]] auto domain_product (int32 levelFrom, int32 levelTo) const
157 template<class NodeOp>
158 auto for_each_son (
node_t*
node, NodeOp&& operation) const ->
void;
160 template<class NodeOp>
163 son_container const& sons,
167 template<class NodeOp>
168 auto for_each_node (NodeOp&& operation) const ->
void;
170 template<class NodeOp>
171 auto for_each_terminal_node (NodeOp&& operation) const ->
void;
179 auto cache_clear () ->
void;
181 template<class NodeOp>
182 auto traverse_pre (
node_t* rootNode, NodeOp operation) const ->
void;
184 template<class NodeOp>
185 auto traverse_post (
node_t* rootNode, NodeOp operation) const ->
void;
187 template<class NodeOp>
188 auto traverse_level (
node_t* rootNode, NodeOp operation) const ->
void;
190 [[nodiscard]] auto is_valid_var_value (int32 index, int32 value) const
193 auto run_deferred () ->
void;
195 static auto dec_ref_count (
node_t*
node) ->
void;
197 auto sift_variables () ->
void;
200 template<class NodeOp>
201 auto traverse_pre_impl (
node_t*
node, NodeOp operation) const ->
void;
203 template<class NodeOp>
204 auto traverse_post_impl (
node_t*
node, NodeOp operation) const ->
void;
206 [[nodiscard]] auto is_redundant (int32 index, son_container const& sons)
209 auto adjust_tables () ->
void;
210 auto adjust_caches () ->
void;
212 auto swap_variable_with_next (int32 index) ->
void;
213 auto swap_node_with_next (
node_t*
node) ->
void;
216 [[nodiscard]] auto make_special_node (int32 value) ->
node_t*;
218 template<class... Args>
219 [[nodiscard]] auto make_new_node (Args&&... args) ->
node_t*;
222 template<class ForEachNode>
223 auto to_dot_graph_common (std::ostream& ost, ForEachNode&& forEach) const
226 auto deferr_gc_reorder () ->
void;
228 auto collect_garbage () ->
void;
230 [[nodiscard]] static auto check_distinct (std::vector<int32> const& ints)
233 [[nodiscard]] static auto can_be_gced (
node_t*
node) ->
bool;
236 static constexpr int32 DEFAULT_FIRST_TABLE_ADJUSTMENT = 230;
237 static constexpr
double DEFAULT_CACHE_RATIO = 1.0;
238 static constexpr
double DEFAULT_GC_RATIO = 0.20;
244 std::vector<
node_t*> terminals_;
245 std::vector<
node_t*> specials_;
246 std::vector<int32> indexToLevel_;
247 std::vector<int32> levelToIndex_;
248 [[no_unique_address]] Domain domains_;
251 int64 adjustmentNodeCount_;
254 bool autoReorderEnabled_;
255 bool gcReorderDeferred_;
258template<class Data, class Degree>
259auto id_inc_ref_count (
node<Data, Degree>* const
node)
260 -> ::teddy::
node<Data, Degree>*
262 node->inc_ref_count();
266template<
class Data,
class Degree>
274template<
class Data,
class Degree>
275auto id_set_notmarked (node<Data, Degree>*
const node)
278 node->set_notmarked();
282template<
class Data,
class Degree,
class Domain>
283node_manager<Data, Degree, Domain>::node_manager(
284 int32
const varCount,
285 int64
const nodePoolSize,
286 int64
const extraNodePoolSize,
287 std::vector<int32> order
289requires(domains::is_fixed<Domain>::value)
296 static_cast<std::vector<int32>&&>(order),
302template<
class Data,
class Degree,
class Domain>
303node_manager<Data, Degree, Domain>::node_manager(
304 int32
const varCount,
305 int64
const nodePoolSize,
306 int64
const extraNodePoolSize,
307 std::vector<int32> order,
308 domains::mixed domains
310requires(domains::is_mixed<Domain>::value)
317 static_cast<std::vector<int32>&&>(order),
318 static_cast<domains::mixed&&>(domains)
323template<
class Data,
class Degree,
class Domain>
324node_manager<Data, Degree, Domain>::node_manager(
325 [[maybe_unused]] common_init_tag initTag,
326 int32
const varCount,
327 int64
const nodePoolSize,
328 int64
const extraNodePoolSize,
329 std::vector<int32> order,
332 opCache_(static_cast<int64>(
333 DEFAULT_CACHE_RATIO * static_cast<double>(nodePoolSize)
335 pool_(nodePoolSize, extraNodePoolSize),
339 indexToLevel_(as_usize(varCount)),
340 levelToIndex_(static_cast<std::vector<int32>&&>(order)),
341 domains_(static_cast<Domain&&>(domains)),
344 adjustmentNodeCount_(DEFAULT_FIRST_TABLE_ADJUSTMENT),
345 cacheRatio_(DEFAULT_CACHE_RATIO),
346 gcRatio_(DEFAULT_GC_RATIO),
347 autoReorderEnabled_(false),
348 gcReorderDeferred_(false)
350 assert(ssize(levelToIndex_) == varCount_);
351 assert(check_distinct(levelToIndex_));
353 if constexpr (domains::is_mixed<Domain>::value)
355 assert(ssize(domains_.domains_) == varCount_);
356 if constexpr (degrees::is_fixed<Degree>::value)
358 for ([[maybe_unused]] int32
const domain : domains_.domains_)
360 assert(domain <= Degree::value);
367 for (int32
const index : levelToIndex_)
369 indexToLevel_[as_uindex(index)] = level++;
380 double constexpr RelPeakPosition = 0.71;
381 double constexpr RelPeakNodeCount = 0.05;
382 double const c = RelPeakPosition * (
static_cast<double>(varCount) - 1);
383 double const fc = RelPeakNodeCount *
static_cast<double>(nodePoolSize);
385 for (int32 i = 0; i <= static_cast<int32>(c); ++i)
387 auto const x =
static_cast<double>(i);
388 uniqueTables_.emplace_back(
389 static_cast<int64
>(fc * x / c),
394 for (
auto i =
static_cast<int32
>(c) + 1; i < varCount_; ++i)
396 auto const n =
static_cast<double>(varCount) - 1;
397 auto const x =
static_cast<double>(i);
398 uniqueTables_.emplace_back(
399 static_cast<int64
>((fc * x) / (c - n) - (fc * n) / (c - n)),
405template<
class Data,
class Degree,
class Domain>
406auto node_manager<Data, Degree, Domain>::set_cache_ratio(
double const ratio)
413template<
class Data,
class Degree,
class Domain>
414auto node_manager<Data, Degree, Domain>::set_gc_ratio(
double const ratio)
417 assert(ratio >= 0.0 && ratio <= 1.0);
421template<
class Data,
class Degree,
class Domain>
422auto node_manager<Data, Degree, Domain>::set_auto_reorder(
bool const doReorder)
425 autoReorderEnabled_ = doReorder;
428template<
class Data,
class Degree,
class Domain>
429auto node_manager<Data, Degree, Domain>::get_terminal_node(int32
const value
432 return value < ssize(terminals_) ? terminals_[as_uindex(value)] :
nullptr;
435template<
class Data,
class Degree,
class Domain>
436auto node_manager<Data, Degree, Domain>::make_terminal_node(int32
const value)
439 if constexpr (domains::is_fixed<Domain>::value)
441 assert(value < Domain::value);
444 if (is_special(value))
446 return this->make_special_node(value);
449 if (value >= ssize(terminals_))
451 terminals_.resize(as_usize(value + 1),
nullptr);
454 if (not terminals_[as_uindex(value)])
456 terminals_[as_uindex(value)] = this->make_new_node(value);
459 return id_set_marked(terminals_[as_uindex(value)]);
462template<
class Data,
class Degree,
class Domain>
463auto node_manager<Data, Degree, Domain>::make_special_node(
464 [[maybe_unused]] int32
const value
467 assert(value == Undefined);
469 if (specials_.empty())
471 specials_.resize(1,
nullptr);
474 if (not specials_[0])
476 specials_[0] = this->make_new_node(Undefined);
479 return id_set_marked(specials_[0]);
482template<
class Data,
class Degree,
class Domain>
483auto node_manager<Data, Degree, Domain>::make_son_container(int32
const domain)
486 return node_t::make_son_container(domain, Degree());
489template<
class Data,
class Degree,
class Domain>
490auto node_manager<Data, Degree, Domain>::make_internal_node(
492 son_container
const& sons
496 if (this->is_redundant(index, sons))
498 node_t*
const son = sons[0];
499 if constexpr (degrees::is_mixed<Degree>::value)
501 node_t::delete_son_container(sons);
507 unique_table<Data, Degree>& table = uniqueTables_[as_uindex(index)];
508 auto const [existing, hash] = table.find(sons);
511 if constexpr (degrees::is_mixed<Degree>::value)
513 node_t::delete_son_container(sons);
515 this->for_each_son(existing, id_set_notmarked<Data, Degree>);
516 return id_set_marked(existing);
520 node_t*
const newNode = this->make_new_node(index, sons);
521 table.insert(newNode, hash);
522 this->for_each_son(newNode, id_inc_ref_count<Data, Degree>);
523 this->for_each_son(newNode, id_set_notmarked<Data, Degree>);
525 return id_set_marked(newNode);
528template<
class Data,
class Degree,
class Domain>
529auto node_manager<Data, Degree, Domain>::get_level(int32
const index)
const
532 return indexToLevel_[as_uindex(index)];
535template<
class Data,
class Degree,
class Domain>
536auto node_manager<Data, Degree, Domain>::get_level(node_t*
const node)
const
539 return node->is_terminal() ? this->get_leaf_level()
540 : this->get_level(node->get_index());
543template<
class Data,
class Degree,
class Domain>
544auto node_manager<Data, Degree, Domain>::get_leaf_level() const -> int32
546 return this->get_var_count();
549template<
class Data,
class Degree,
class Domain>
550auto node_manager<Data, Degree, Domain>::get_index(int32
const level)
const
553 assert(level < ssize(levelToIndex_));
554 return levelToIndex_[as_uindex(level)];
557template<
class Data,
class Degree,
class Domain>
558auto node_manager<Data, Degree, Domain>::get_domain(int32
const index)
const
561 assert(index < this->get_var_count());
562 return domains_[index];
565template<
class Data,
class Degree,
class Domain>
566auto node_manager<Data, Degree, Domain>::get_domain(node_t*
const node)
const
569 return this->get_domain(node->get_index());
572template<
class Data,
class Degree,
class Domain>
573auto node_manager<Data, Degree, Domain>::get_node_count(int32
const index)
const
576 assert(index < this->get_var_count());
577 return uniqueTables_[as_uindex(index)].get_size();
580template<
class Data,
class Degree,
class Domain>
581auto node_manager<Data, Degree, Domain>::get_node_count(node_t*
const node
585 this->traverse_pre(node, [&count] (node_t*) { ++count; });
589template<
class Data,
class Degree,
class Domain>
590auto node_manager<Data, Degree, Domain>::get_node_count() const -> int64
595template<
class Data,
class Degree,
class Domain>
596auto node_manager<Data, Degree, Domain>::get_var_count() const -> int32
601template<
class Data,
class Degree,
class Domain>
602auto node_manager<Data, Degree, Domain>::get_order() const
603 -> std::vector<int32> const&
605 return levelToIndex_;
608template<
class Data,
class Degree,
class Domain>
609auto node_manager<Data, Degree, Domain>::get_domains() const
610 -> std::vector<int32>
612 std::vector<int32> domains;
613 domains.reserve(as_usize(varCount_));
614 for (int32 k = 0; k < varCount_; ++k)
616 domains.push_back(domains_[k]);
621template<
class Data,
class Degree,
class Domain>
622auto node_manager<Data, Degree, Domain>::force_gc() ->
void
624 this->collect_garbage();
625 opCache_.remove_unused();
628template<
class Data,
class Degree,
class Domain>
629auto node_manager<Data, Degree, Domain>::collect_garbage() ->
void
631#ifdef LIBTEDDY_VERBOSE
632 debug::out(
"node_manager::collect_garbage, ");
633 int64
const before = nodeCount_;
636 for (int32 level = 0; level < this->get_var_count(); ++level)
638 int32
const index = levelToIndex_[as_uindex(level)];
639 auto& table = uniqueTables_[as_uindex(index)];
640 auto const endIt = table.end();
641 auto tableIt = table.begin();
643 while (tableIt != endIt)
645 node_t*
const node = *tableIt;
646 if (can_be_gced(node))
648 this->for_each_son(node, dec_ref_count);
649 tableIt = table.erase(tableIt);
650 this->delete_node(node);
659 for (node_t*& node : terminals_)
661 if (node && can_be_gced(node))
663 this->delete_node(node);
668 for (node_t*& node : specials_)
670 if (node && can_be_gced(node))
672 this->delete_node(node);
677#ifdef LIBTEDDY_VERBOSE
688template<
class Data,
class Degree,
class Domain>
689auto node_manager<Data, Degree, Domain>::to_dot_graph(std::ostream& ost)
const
692 this->to_dot_graph_common(
694 [
this] (
auto const& operation) { this->for_each_node(operation); }
698template<
class Data,
class Degree,
class Domain>
699auto node_manager<Data, Degree, Domain>::to_dot_graph(
704 this->to_dot_graph_common(
706 [
this, node] (
auto const& operation)
707 { this->traverse_pre(node, operation); }
711template<
class Data,
class Degree,
class Domain>
712auto node_manager<Data, Degree, Domain>::domain_product(
713 int32
const levelFrom,
717 if constexpr (domains::is_fixed<Domain>::value && Degree::value == 2)
719 return int64(1) << (levelTo - levelFrom);
721 else if constexpr (domains::is_fixed<Domain>::value)
723 return utils::int_pow(Domain::value, levelTo - levelFrom);
728 for (int32 level = levelFrom; level < levelTo; ++level)
730 product *= domains_[levelToIndex_[as_uindex(level)]];
736template<
class Data,
class Degree,
class Domain>
737template<
class NodeOp>
738auto node_manager<Data, Degree, Domain>::for_each_son(
743 int32
const index = node->get_index();
744 for (int32 k = 0; k < domains_[index]; ++k)
746 operation(node->get_son(k));
750template<
class Data,
class Degree,
class Domain>
751template<
class NodeOp>
752auto node_manager<Data, Degree, Domain>::for_each_son(
754 son_container
const& sons,
758 for (int32 k = 0; k < domains_[index]; ++k)
760 operation(sons[as_uindex(k)]);
764template<
class Data,
class Degree,
class Domain>
765template<
class NodeOp>
766auto node_manager<Data, Degree, Domain>::for_each_node(NodeOp&& operation)
const
769 for (unique_table<Data, Degree>
const& table : uniqueTables_)
771 for (node_t*
const node : table)
777 this->for_each_terminal_node(operation);
780template<
class Data,
class Degree,
class Domain>
781template<
class NodeOp>
782auto node_manager<Data, Degree, Domain>::for_each_terminal_node(
786 for (node_t*
const node : terminals_)
795template<
class Data,
class Degree,
class Domain>
796template<teddy_bin_op O>
797auto node_manager<Data, Degree, Domain>::cache_find(node_t* lhs, node_t* rhs)
800 if constexpr (O::is_commutative())
804 utils::swap(lhs, rhs);
807 node_t*
const node = opCache_.find(O::get_id(), lhs, rhs);
815template<
class Data,
class Degree,
class Domain>
816template<teddy_bin_op O>
817auto node_manager<Data, Degree, Domain>::cache_put(
818 node_t*
const result,
823 if constexpr (O::is_commutative())
827 utils::swap(lhs, rhs);
830 opCache_.put(O::get_id(), result, lhs, rhs);
833template<
class Data,
class Degree,
class Domain>
834auto node_manager<Data, Degree, Domain>::cache_clear() ->
void
839template<
class Data,
class Degree,
class Domain>
840auto node_manager<Data, Degree, Domain>::is_valid_var_value(
845 return value < domains_[index];
848template<
class Data,
class Degree,
class Domain>
849auto node_manager<Data, Degree, Domain>::run_deferred() ->
void
851 if (gcReorderDeferred_)
853 this->collect_garbage();
855 this->sift_variables();
859template<
class Data,
class Degree,
class Domain>
860template<
class NodeOp>
861auto node_manager<Data, Degree, Domain>::traverse_pre(
862 node_t*
const rootNode,
863 NodeOp
const operation
866 this->traverse_pre_impl(rootNode, operation);
867 this->traverse_pre_impl(rootNode, [] (node_t*) {});
871template<
class Data,
class Degree,
class Domain>
872template<
class NodeOp>
873auto node_manager<Data, Degree, Domain>::traverse_pre_impl(
875 NodeOp
const operation
878 node->toggle_marked();
880 if (node->is_internal())
882 int32
const nodeDomain = this->get_domain(node);
883 for (int32 k = 0; k < nodeDomain; ++k)
885 node_t*
const son = node->get_son(k);
886 if (node->is_marked() != son->is_marked())
888 this->traverse_pre_impl(son, operation);
894template<
class Data,
class Degree,
class Domain>
895template<
class NodeOp>
896auto node_manager<Data, Degree, Domain>::traverse_post(
897 node_t*
const rootNode,
901 this->traverse_post_impl(rootNode, operation);
902 this->traverse_post_impl(rootNode, [] (node_t*) {});
906template<
class Data,
class Degree,
class Domain>
907template<
class NodeOp>
908auto node_manager<Data, Degree, Domain>::traverse_post_impl(
913 node->toggle_marked();
914 if (node->is_internal())
916 int32
const nodeDomain = this->get_domain(node);
917 for (int32 k = 0; k < nodeDomain; ++k)
919 node_t*
const son = node->get_son(k);
920 if (node->is_marked() != son->is_marked())
922 this->traverse_post_impl(son, operation);
929template<
class Data,
class Degree,
class Domain>
930template<
class NodeOp>
931auto node_manager<Data, Degree, Domain>::traverse_level(
932 node_t*
const rootNode,
936 std::vector<std::vector<node_t*>> buckets(as_usize(varCount_) + 1);
937 auto const endBucketIt = end(buckets);
938 auto bucketIt = begin(buckets) + this->get_level(rootNode);
939 (*bucketIt).push_back(rootNode);
940 rootNode->toggle_marked();
942 while (bucketIt != endBucketIt)
944 for (node_t*
const node : *bucketIt)
947 if (node->is_internal())
949 int32
const domain = this->get_domain(node);
950 for (int32 k = 0; k < domain; ++k)
952 node_t*
const son = node->get_son(k);
953 if (son->is_marked() != node->is_marked())
955 int32
const level = this->get_level(son);
956 buckets[as_uindex(level)].push_back(son);
957 son->toggle_marked();
966 }
while (bucketIt != endBucketIt && (*bucketIt).empty());
970 this->traverse_pre_impl(rootNode, [] (node_t*) {});
973template<
class Data,
class Degree,
class Domain>
974auto node_manager<Data, Degree, Domain>::dec_ref_count(node_t*
const node)
977 node->dec_ref_count();
980template<
class Data,
class Degree,
class Domain>
981auto node_manager<Data, Degree, Domain>::is_redundant(
983 son_container
const& sons
986 for (int32 j = 1; j < domains_[index]; ++j)
988 if (sons[as_uindex(j - 1)] != sons[as_uindex(j)])
996template<
class Data,
class Degree,
class Domain>
997auto node_manager<Data, Degree, Domain>::adjust_tables() ->
void
999#ifdef LIBTEDDY_VERBOSE
1001 "node_manager::adjust_tables\tAdjusting unique tables.",
1008 for (int32 i = 0; i < ssize(uniqueTables_); ++i)
1010 uniqueTables_[as_uindex(i)].adjust_capacity();
1014template<
class Data,
class Degree,
class Domain>
1015auto node_manager<Data, Degree, Domain>::adjust_caches() ->
void
1017 auto const newCapacity = cacheRatio_ *
static_cast<double>(nodeCount_);
1018 opCache_.grow_capacity(
static_cast<int64
>(newCapacity));
1021template<
class Data,
class Degree,
class Domain>
1022template<
class... Args>
1023auto node_manager<Data, Degree, Domain>::make_new_node(Args&&... args)
1026 if (autoReorderEnabled_)
1032 if (pool_.get_available_node_count() == 0)
1035 this->deferr_gc_reorder();
1043 if (pool_.get_available_node_count() == 0)
1045 auto const growThreshold =
static_cast<int64
>(
1046 gcRatio_ *
static_cast<double>(nodeCount_)
1051 if (pool_.get_available_node_count() < growThreshold)
1058 if (nodeCount_ >= adjustmentNodeCount_)
1062 this->adjust_tables();
1063 this->adjust_caches();
1064 adjustmentNodeCount_ = 2 * adjustmentNodeCount_ / 1;
1070 return pool_.create(args...);
1073template<
class Data,
class Degree,
class Domain>
1074auto node_manager<Data, Degree, Domain>::delete_node(node_t*
const n) ->
void
1076 assert(not n->is_marked());
1082template<
class Data,
class Degree,
class Domain>
1083template<
class ForEachNode>
1084auto node_manager<Data, Degree, Domain>::to_dot_graph_common(
1086 ForEachNode&& forEach
1089 auto const make_label = [] (node_t*
const node)
1091 if (node->is_terminal())
1093 using namespace std::literals::string_literals;
1094 int32
const val = node->get_value();
1095 return val == Undefined ?
"*"s : std::to_string(val);
1098 return "x" + std::to_string(node->get_index());
1101 auto const get_id_str = [] (node_t*
const n)
1102 {
return std::to_string(
reinterpret_cast<uint64
>(n)); };
1104 auto const output_range = [] (
auto& ostr,
auto const& range,
auto const sep)
1106 auto const endIt = end(range);
1107 auto rangeIt = begin(range);
1108 while (rangeIt != endIt)
1112 if (rangeIt != endIt)
1119 auto const levelCount = as_usize(1 + this->get_var_count());
1120 std::vector<std::string> labels;
1121 std::vector<std::vector<std::string>> rankGroups(levelCount);
1122 std::vector<std::string> arcs;
1123 std::vector<std::string> squareShapes;
1126 [&,
this] (node_t*
const node)
1129 int32
const level = this->get_level(node);
1130 labels.emplace_back(
1131 get_id_str(node) + R
"( [label = ")" + make_label(node)
1132 + R"(", tooltip = ")" + std::to_string(node->get_ref_count())
1136 if (node->is_terminal())
1138 squareShapes.emplace_back(get_id_str(node));
1139 rankGroups.back().emplace_back(get_id_str(node) +
";");
1144 rankGroups[as_uindex(level)].emplace_back(get_id_str(node) +
";");
1149 [&, sonOrder = 0] (node_t*
const son)
mutable
1151 if constexpr (std::is_same_v<Degree, degrees::fixed<2>>)
1154 get_id_str(node) +
" -> " + get_id_str(son)
1156 + (0 == sonOrder ?
"dashed" :
"solid") +
"];"
1162 get_id_str(node) +
" -> " + get_id_str(son)
1163 + R
"( [label = )" + std::to_string(sonOrder) + "];"
1173 ost <<
"digraph DD {" <<
'\n';
1174 ost <<
" node [shape = square] ";
1175 output_range(ost, squareShapes,
" ");
1177 ost <<
" node [shape = circle];"
1181 output_range(ost, labels,
"\n ");
1184 output_range(ost, arcs,
"\n ");
1187 for (std::vector<std::string>
const& ranks : rankGroups)
1189 if (not ranks.empty())
1191 ost <<
" { rank = same; ";
1192 output_range(ost, ranks,
" ");
1193 ost <<
" }" <<
'\n';
1200template<
class Data,
class Degree,
class Domain>
1201auto node_manager<Data, Degree, Domain>::deferr_gc_reorder() ->
void
1203 gcReorderDeferred_ =
true;
1206template<
class Data,
class Degree,
class Domain>
1207auto node_manager<Data, Degree, Domain>::check_distinct(
1208 std::vector<int32>
const& ints
1216 int32
const maxElem = *utils::max_elem(ints.begin(), ints.end());
1217 std::vector<bool> bitset(as_usize(maxElem + 1),
false);
1218 for (int32
const checkInt : ints)
1220 if (bitset[as_uindex(checkInt)])
1224 bitset[as_uindex(checkInt)] =
true;
1229template<
class Data,
class Degree,
class Domain>
1230auto node_manager<Data, Degree, Domain>::can_be_gced(node_t*
const node) ->
bool
1232 return node->get_ref_count() == 0 && not node->is_marked();
1235template<
class Data,
class Degree,
class Domain>
1236auto node_manager<Data, Degree, Domain>::swap_node_with_next(node_t*
const node)
1239 using node_matrix = utils::type_if<
1240 degrees::is_fixed<Degree>::value,
1241 node_t * [Degree::value][Degree::value],
1242 std::vector<std::vector<node_t*>>>::type;
1244 int32
const nodeIndex = node->get_index();
1245 int32
const nextIndex = this->get_index(1 + this->get_level(node));
1246 int32
const nodeDomain = this->get_domain(nodeIndex);
1247 int32
const nextDomain = this->get_domain(nextIndex);
1248 son_container oldSons = this->make_son_container(nodeDomain);
1249 for (int32 k = 0; k < nodeDomain; ++k)
1251 oldSons[k] = node->get_son(k);
1254 node_matrix cofactorMatrix;
1255 if constexpr (degrees::is_mixed<Degree>::value)
1257 cofactorMatrix.resize(
1258 as_usize(nodeDomain),
1259 std::vector<node_t*>(as_usize(nextDomain))
1263 for (
auto nk = 0; nk < nodeDomain; ++nk)
1265 node_t*
const son = node->get_son(nk);
1266 for (
auto sk = 0; sk < nextDomain; ++sk)
1268 bool const justUseSon
1269 = son->is_terminal() || son->get_index() != nextIndex;
1270 cofactorMatrix[as_uindex(nk)][as_uindex(sk)]
1271 = justUseSon ? son : son->get_son(sk);
1275 son_container outerSons = this->make_son_container(nextDomain);
1276 for (int32 outerK = 0; outerK < nextDomain; ++outerK)
1278 son_container innerSons = this->make_son_container(nodeDomain);
1279 for (int32 innerK = 0; innerK < nodeDomain; ++innerK)
1282 = cofactorMatrix[as_uindex(innerK)][as_uindex(outerK)];
1284 outerSons[outerK] = this->make_internal_node(nodeIndex, innerSons);
1287 node->set_index(nextIndex);
1288 node->set_sons(outerSons);
1290 for (int32 k = 0; k < nextDomain; ++k)
1292 node->get_son(k)->inc_ref_count();
1293 node->get_son(k)->set_notmarked();
1296 for (int32 k = 0; k < nodeDomain; ++k)
1298 this->dec_ref_try_gc(oldSons[k]);
1301 if constexpr (degrees::is_mixed<Degree>::value)
1303 node_t::delete_son_container(oldSons);
1307template<
class Data,
class Degree,
class Domain>
1308auto node_manager<Data, Degree, Domain>::dec_ref_try_gc(node_t*
const node)
1311 node->dec_ref_count();
1313 if (not can_be_gced(node))
1318 if (node->is_internal())
1320 int32
const nodeDomain = this->get_domain(node);
1321 for (int32 k = 0; k < nodeDomain; ++k)
1323 this->dec_ref_try_gc(node->get_son(k));
1326 uniqueTables_[as_uindex(node->get_index())].erase(node);
1330 if (is_special(node->get_value()))
1332 specials_[as_uindex(special_to_index(node->get_value()))] =
nullptr;
1336 terminals_[as_uindex(node->get_value())] =
nullptr;
1340 this->delete_node(node);
1343template<
class Data,
class Degree,
class Domain>
1344auto node_manager<Data, Degree, Domain>::swap_variable_with_next(
1348 int32
const level = this->get_level(index);
1349 int32
const nextIndex = this->get_index(1 + level);
1350 unique_table<Data, Degree> tmpTable(uniqueTables_[as_uindex(index)]);
1351 uniqueTables_[as_uindex(index)].clear();
1352 for (node_t*
const node : tmpTable)
1354 this->swap_node_with_next(node);
1356 uniqueTables_[as_uindex(index)].adjust_capacity();
1357 uniqueTables_[as_uindex(nextIndex)].merge(
1358 static_cast<unique_table<Data, Degree>&&
>(tmpTable)
1362 levelToIndex_[as_uindex(level)],
1363 levelToIndex_[as_uindex(1 + level)]
1365 ++indexToLevel_[as_uindex(index)];
1366 --indexToLevel_[as_uindex(nextIndex)];
1369template<
class Data,
class Degree,
class Domain>
1370auto node_manager<Data, Degree, Domain>::sift_variables() ->
void
1372 using count_pair =
struct
1379 auto const determine_sift_order = [
this] ()
1381 std::vector<count_pair> counts;
1382 counts.reserve(as_usize(varCount_));
1383 for (int32 index = 0; index < varCount_; ++index)
1385 counts.push_back(count_pair {index, this->get_node_count(index)});
1389 [] (count_pair
const& lhs, count_pair
const& rhs)
1390 {
return lhs.count_ > rhs.count_; }
1396 auto const move_var_down
1397 = [
this] (
auto const index) { this->swap_variable_with_next(index); };
1400 auto const move_var_up = [
this] (
auto const index)
1402 int32
const level = this->get_level(index);
1403 int32
const prevIndex = this->get_index(level - 1);
1404 this->swap_variable_with_next(prevIndex);
1409 auto const place_variable = [&,
this] (
auto const index)
1411 int32
const lastInternalLevel = this->get_var_count() - 1;
1412 int32 currentLevel = this->get_level(index);
1413 int32 optimalLevel = currentLevel;
1414 int64 optimalCount = nodeCount_;
1417 while (currentLevel != lastInternalLevel)
1419 move_var_down(index);
1421 if (nodeCount_ < optimalCount)
1423 optimalCount = nodeCount_;
1424 optimalLevel = currentLevel;
1429 while (currentLevel != 0)
1433 if (nodeCount_ < optimalCount)
1435 optimalCount = nodeCount_;
1436 optimalLevel = currentLevel;
1441 while (currentLevel != optimalLevel)
1443 move_var_down(index);
1448#ifdef LIBTEDDY_VERBOSE
1450 "node_manager: Sifting variables. Node count before ",
1456 auto const siftOrder = determine_sift_order();
1457 for (
auto const pair : siftOrder)
1459 place_variable(pair.index_);
1462#ifdef LIBTEDDY_VERBOSE
1464 "node_manager: Done sifting. Node count after ",
1470 gcReorderDeferred_ =
false;
Cache for the apply opertaion.
Definition hash_tables.hpp:255
Definition node_manager.hpp:82
Definition node_manager.hpp:88
Definition node_pool.hpp:17
Table of unique nodes.
Definition hash_tables.hpp:71
Definition operators.hpp:293
Definition node_manager.hpp:44
Definition node_manager.hpp:57
Definition node_manager.hpp:69
Definition node_manager.hpp:25