From e0d178e981c7319985b5497e1e977df1b30b2f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Mon, 17 Jun 2024 09:11:43 +0200 Subject: [PATCH 01/30] Add missing '_' prefix to '__dd' and 'dd' class member variables and extend comments to column 100 --- src/adiar/bdd/bdd.cpp | 4 +- src/adiar/bdd/if_then_else.cpp | 86 ++-- src/adiar/bdd/negate.cpp | 6 +- src/adiar/internal/algorithms/convert.h | 6 +- .../internal/algorithms/nested_sweeping.h | 4 +- src/adiar/internal/algorithms/pred.cpp | 61 ++- src/adiar/internal/algorithms/pred.h | 67 ++- src/adiar/internal/algorithms/reduce.h | 2 +- src/adiar/internal/algorithms/replace.h | 4 +- .../internal/data_structures/level_merger.h | 34 +- src/adiar/internal/dd.h | 392 +++++++++--------- src/adiar/internal/dd_func.h | 53 ++- src/adiar/internal/io/levelized_file_stream.h | 129 +++--- .../internal/io/node_arc_random_access.h | 2 +- src/adiar/internal/io/node_arc_stream.h | 2 +- src/adiar/internal/io/node_stream.h | 44 +- src/adiar/zdd/pred.cpp | 18 +- src/adiar/zdd/zdd.cpp | 4 +- src/adiar/zdd/zdd.h | 4 +- test/adiar/bdd/test_apply.cpp | 22 +- test/adiar/bdd/test_bdd.cpp | 10 +- test/adiar/bdd/test_if_then_else.cpp | 12 +- test/adiar/bdd/test_quantify.cpp | 12 +- test/adiar/bdd/test_restrict.cpp | 14 +- test/adiar/zdd/test_complement.cpp | 4 +- test/adiar/zdd/test_zdd.cpp | 8 +- test/test.h | 4 +- 27 files changed, 488 insertions(+), 520 deletions(-) diff --git a/src/adiar/bdd/bdd.cpp b/src/adiar/bdd/bdd.cpp index 47e1d2cc4..4fbcbb918 100644 --- a/src/adiar/bdd/bdd.cpp +++ b/src/adiar/bdd/bdd.cpp @@ -77,8 +77,8 @@ namespace adiar bdd& bdd::operator=(const bdd& other) { - this->negate = other.negate; - this->file = other.file; + this->_negate = other._negate; + this->_file = other._file; return *this; } diff --git a/src/adiar/bdd/if_then_else.cpp b/src/adiar/bdd/if_then_else.cpp index fa42bc2a9..1f4a97881 100644 --- a/src/adiar/bdd/if_then_else.cpp +++ b/src/adiar/bdd/if_then_else.cpp @@ -22,18 +22,17 @@ namespace adiar { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// // Struct to hold statistics statistics::prod3_t stats_prod3; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// // Data structures // - // To make the merge simpler we will make sure that 'data_1_x' and 'data_2_x' - // are ordered based on the order of the BDDs are given, i.e. the elements of - // the if-BDD would only every be forwarded in 'data_1_x'. The then-elements - // are forwarded only in 'data_2_x' if the if-BDD is also forwarded. Finally, - // the placement of the else-BDD on whether any element from the if-BDD or + // To make the merge simpler we will make sure that 'data_1_x' and 'data_2_x' are ordered based on + // the order of the BDDs are given, i.e. the elements of the if-BDD would only every be forwarded + // in 'data_1_x'. The then-elements are forwarded only in 'data_2_x' if the if-BDD is also + // forwarded. Finally, the placement of the else-BDD on whether any element from the if-BDD or // then-BDD has been forwarded. template @@ -55,14 +54,13 @@ namespace adiar using ite_priority_queue_3_t = internal:: priority_queue, internal::request_data_third_lt>>; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// // Helper functions internal::shared_levelized_file __ite_zip_bdds(const bdd& bdd_if, const bdd& bdd_then, const bdd& bdd_else) { - // TODO: What is the performance of '<<' rather than 'unsafe_push'? If there - // is a major difference, then we may want to "inline" the '<<' with its - // _canonical check here. + // TODO: What is the performance of '<<' rather than 'unsafe_push'? If there is a major + // difference, then we may want to "inline" the '<<' with its _canonical check here. internal::node::pointer_type root_then = internal::node::pointer_type::nil(); internal::node::pointer_type root_else = internal::node::pointer_type::nil(); @@ -194,9 +192,8 @@ namespace adiar const size_t pq_3_memory, const size_t max_pq_3_size) { - // Now, at this point we will not defer to using the Apply, so we can take - // up memory by opening the input streams and evaluating trivial - // conditionals. + // Now, at this point we will not defer to using the Apply, so we can take up memory by opening + // the input streams and evaluating trivial conditionals. internal::node_stream<> in_nodes_if(bdd_if); internal::node v_if = in_nodes_if.pull(); @@ -208,9 +205,8 @@ namespace adiar internal::node_stream<> in_nodes_else(bdd_else); internal::node v_else = in_nodes_else.pull(); - // If the levels of 'then' and 'else' are disjoint and the 'if' BDD is above - // the two others, then we can merely zip the 'then' and 'else' BDDs. This - // is only O((N1+N2+N3)/B) I/Os! + // If the levels of 'then' and 'else' are disjoint and the 'if' BDD is above the two others, + // then we can merely zip the 'then' and 'else' BDDs. This is only O((N1+N2+N3)/B) I/Os! if (bdd_maxvar(bdd_if) < v_then.label() && bdd_maxvar(bdd_if) < v_else.label() && internal::disjoint_levels(bdd_then, bdd_else)) { return __ite_zip_bdds(bdd_if, bdd_then, bdd_else); @@ -314,9 +310,8 @@ namespace adiar if (ite_must_forward(v_if, req.target[0], out_label, t_seek) || ite_must_forward(v_then, req.target[1], out_label, t_seek) || ite_must_forward(v_else, req.target[2], out_label, t_seek)) { - // An element should be forwarded, if it was not already forwarded - // (t_seek <= t_x), if it isn't the last one to seek (t_x < t_third), and - // if we actually are holding it. + // An element should be forwarded, if it was not already forwarded (t_seek <= t_x), if it + // isn't the last one to seek (t_x < t_third), and if we actually are holding it. const bool forward_if = (t_seek <= req.target[0]) && (req.target[0] < t_third) && (v_if.uid() == req.target[0]); @@ -450,10 +445,10 @@ namespace adiar return __bdd(out_arcs, ep); } - ////////////////////////////////////////////////////////////////////////////// - /// Derives an upper bound on the output's maximum i-level cut based on the - /// product of the maximum i-level cut of all three inputs. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Derives an upper bound on the output's maximum i-level cut based on the product of the maximum + /// i-level cut of all three inputs. + ////////////////////////////////////////////////////////////////////////////////////////////////// template size_t __ite_ilevel_upper_bound(const internal::dd& in_if, @@ -491,9 +486,9 @@ namespace adiar + if_cut_trues * then_cut_internal + if_cut_falses * else_cut_internal + const_size_inc); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// Derives an upper bound on the output's maximum i-level cut given its size. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// size_t __ite_ilevel_upper_bound(const internal::dd& in_if, const internal::dd& in_then, @@ -503,34 +498,32 @@ namespace adiar const internal::safe_size_t then_size = in_then->size(); const internal::safe_size_t else_size = in_else->size(); - // Compute the number of triples (t_if, t_then, t_else) where t_if is an - // internal node and t_then and t_else are nodes or (mismatching) terminals. - // Then also count the copies of in_then and in_else for when in_if hits a - // terminal early. + // Compute the number of triples (t_if, t_then, t_else) where t_if is an internal node and + // t_then and t_else are nodes or (mismatching) terminals. Then also count the copies of in_then + // and in_else for when in_if hits a terminal early. return internal::to_size(if_size * ((then_size + 2u) * (else_size + 2u) - 2u) + then_size + else_size + 1u + 2u); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// __bdd bdd_ite(const exec_policy& ep, const bdd& f, const bdd& g, const bdd& h) { - // There are multiple cases, where this boils down to an Apply rather than - // an If-Then-Else. The bdd_apply uses tuples rather than triples and only - // two priority queues, so it will run considerably faster. + // There are multiple cases, where this boils down to an Apply rather than an If-Then-Else. The + // bdd_apply uses tuples rather than triples and only two priority queues, so it will run + // considerably faster. // - // The translations into Apply can be found in Figure 1 of "Efficient - // Implementation of a BDD Package" of Karl S. Brace, Richard L. Rudell, and - // Randal E. Bryant. + // The translations into Apply can be found in Figure 1 of "Efficient Implementation of a BDD + // Package" of Karl S. Brace, Richard L. Rudell, and Randal E. Bryant. // Resolve being given the same underlying file in both cases - if (g.file == h.file) { return g.negate == h.negate ? __bdd(g) : bdd_xnor(f, g); } + if (g._file == h._file) { return g._negate == h._negate ? __bdd(g) : bdd_xnor(f, g); } // Resolve being given the same underlying file for conditional and a case - if (f.file == g.file) { - return f.negate == g.negate ? bdd_or(f, h) : bdd_and(bdd_not(f), h); - } else if (f.file == h.file) { - return f.negate == h.negate ? bdd_and(f, g) : bdd_imp(f, g); + if (f._file == g._file) { + return f._negate == g._negate ? bdd_or(f, h) : bdd_and(bdd_not(f), h); + } else if (f._file == h._file) { + return f._negate == h._negate ? bdd_and(f, g) : bdd_imp(f, g); } // Resolve being given a terminal in one of the cases @@ -540,12 +533,11 @@ namespace adiar return bdd_apply(f, g, dd_valueof(h) ? imp_op : and_op); } - // Compute amount of memory available for auxiliary data structures after - // having opened all streams. + // Compute amount of memory available for auxiliary data structures after having opened all + // streams. // - // We then may derive an upper bound on the size of auxiliary data - // structures and check whether we can run them with a faster internal - // memory variant. + // We then may derive an upper bound on the size of auxiliary data structures and check whether + // we can run them with a faster internal memory variant. const tpie::memory_size_type aux_available_memory = internal::memory_available() // Input streams - 3 * internal::node_stream<>::memory_usage() diff --git a/src/adiar/bdd/negate.cpp b/src/adiar/bdd/negate.cpp index cca0057ee..dfb79b299 100644 --- a/src/adiar/bdd/negate.cpp +++ b/src/adiar/bdd/negate.cpp @@ -7,15 +7,15 @@ namespace adiar bdd bdd_not(const bdd& in) { - bdd out = in; - out.negate = !in.negate; + bdd out = in; + out._negate = !in._negate; return out; } bdd bdd_not(bdd&& b) { - b.negate = !b.negate; + b._negate = !b._negate; return std::move(b); } } diff --git a/src/adiar/internal/algorithms/convert.h b/src/adiar/internal/algorithms/convert.h index ab965fa20..d2d303f38 100644 --- a/src/adiar/internal/algorithms/convert.h +++ b/src/adiar/internal/algorithms/convert.h @@ -47,7 +47,7 @@ namespace adiar::internal static typename to_policy::dd_type on_empty_labels(const typename from_policy::dd_type& dd) { - return typename to_policy::dd_type(dd.file, dd.negate); + return typename to_policy::dd_type(dd._file, dd._negate); } static typename to_policy::dd_type @@ -80,8 +80,8 @@ namespace adiar::internal nw.unsafe_push(next_node); nw.unsafe_push(level_info(next_label, 1u)); } else { - // If we kill the resulting node once, then we will also do it for all - // the other labels we still are missing. + // If we kill the resulting node once, then we will also do it for all the other labels we + // still are missing. has_output = false; break; } diff --git a/src/adiar/internal/algorithms/nested_sweeping.h b/src/adiar/internal/algorithms/nested_sweeping.h index bc3805205..5c931c7e1 100644 --- a/src/adiar/internal/algorithms/nested_sweeping.h +++ b/src/adiar/internal/algorithms/nested_sweeping.h @@ -2095,13 +2095,13 @@ namespace adiar::internal // Is it a terminal? if (input.template has() && input.template get()->is_terminal()) { - return reduced_t(input.template get(), input.negate); + return reduced_t(input.template get(), input._negate); } // Otherwise obtain the semi-transposed DAG (construct it if necessary) const shared_arc_file_type dag = input.template has() ? input.template get() - : transpose(reduced_t(input.template get(), input.negate)); + : transpose(reduced_t(input.template get(), input._negate)); // Compute amount of memory available for auxiliary data structures after having opened all // streams. diff --git a/src/adiar/internal/algorithms/pred.cpp b/src/adiar/internal/algorithms/pred.cpp index 06f4121ca..fcaadb124 100644 --- a/src/adiar/internal/algorithms/pred.cpp +++ b/src/adiar/internal/algorithms/pred.cpp @@ -9,14 +9,13 @@ namespace adiar::internal { statistics::equality_t stats_equality; - ////////////////////////////////////////////////////////////////////////////// - // Slow O(sort(N)) I/Os comparison by traversing the product construction and - // comparing each related pair of nodes. - - ////////////////////////////////////////////////////////////////////////////// - // Check whether more requests were processed on this level than allowed. An - // isomorphic DAG would not create more requests than the original number of - // nodes. + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Slow O(sort(N)) I/Os comparison by traversing the product construction and comparing each + // related pair of nodes. + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // Check whether more requests were processed on this level than allowed. An isomorphic DAG would + // not create more requests than the original number of nodes. template class input_bound_levels { @@ -74,14 +73,14 @@ namespace adiar::internal static constexpr bool termination_value = tv; }; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Policy for isomorphism checking with `comparison_check`. /// /// \pre To use this operation, the following should be satisfied. /// - The number of nodes are the same /// - The number of levels are the same /// - The label and size of each level are the same - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// // TODO (Decision Diagrams with other kinds of pointers): // template class isomorphism_policy @@ -155,26 +154,24 @@ namespace adiar::internal static constexpr bool no_early_return_value = true; }; - ////////////////////////////////////////////////////////////////////////////// - /// Fast 2N/B I/Os comparison by comparing the i'th nodes numerically. This - /// requires, that the shared_levelized_file is 'canonical' in the - /// following sense: + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// Fast 2N/B I/Os comparison by comparing the i'th nodes numerically. This requires, that the + /// shared_levelized_file is 'canonical' in the following sense: /// /// - For each level, the ids are decreasing from max_id in increments of one. /// - There are no duplicate nodes. - /// - Nodes within each level are sorted by the children (e.g. ordered first on - /// 'high', secondly on 'low'). + /// - Nodes within each level are sorted by the children (e.g. ordered first on 'high', secondly + /// on 'low'). /// - /// \remark See Section 3.3 in 'Efficient Binary Decision Diagram Manipulation - /// in External Memory' on arXiv (v2 or newer) for an induction proof - /// this is a valid comparison. + /// \remark See Section 3.3 in 'Efficient Binary Decision Diagram Manipulation in External Memory' + /// on arXiv (v2 or newer) for an induction proof this is a valid comparison. /// /// \pre The following are satisfied: /// (1) The number of nodes are the same (to simplify the 'while' condition) /// (2) Both shared_levelized_files are 'canonical'. /// (3) The negation flags given to both shared_levelized_files agree /// (breaks canonicity) - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// bool fast_isomorphism_check(const shared_levelized_file& f0, const shared_levelized_file& f1) @@ -194,7 +191,7 @@ namespace adiar::internal return true; } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// bool is_isomorphic(const exec_policy& ep, const shared_levelized_file& f0, @@ -210,8 +207,7 @@ namespace adiar::internal return negate0 == negate1; } - // Are they trivially not the same, since they have different number of - // nodes? + // Are they trivially not the same, since they have different number of nodes? if (f0->size() != f1->size()) { #ifdef ADIAR_STATS stats_equality.exit_on_nodecount += 1u; @@ -227,8 +223,7 @@ namespace adiar::internal return false; } - // Are they trivially not the same, since they have different number of - // terminal arcs? + // Are they trivially not the same, since they have different number of terminal arcs? if (f0->number_of_terminals[negate0] != f1->number_of_terminals[negate1] || f0->number_of_terminals[!negate0] != f1->number_of_terminals[!negate1]) { #ifdef ADIAR_STATS @@ -237,8 +232,7 @@ namespace adiar::internal return false; } - // Are they trivially not the same, since they have different number of - // levels? + // Are they trivially not the same, since they have different number of levels? if (f0->levels() != f1->levels()) { #ifdef ADIAR_STATS stats_equality.exit_on_varcount += 1u; @@ -246,8 +240,7 @@ namespace adiar::internal return false; } - // Are they trivially not the same, since the labels or the size of each - // level does not match? + // Are they trivially not the same, since the labels or the size of each level does not match? { // Create new scope to garbage collect the two meta_streams early level_info_stream<> in_meta_0(f0); level_info_stream<> in_meta_1(f1); @@ -263,12 +256,10 @@ namespace adiar::internal } } - // TODO: Use 'fast_isomorphism_check' when there is only one node per level. - // In this case, we can just ignore the id (and only focus on the label and - // terminal values). + // TODO: Use 'fast_isomorphism_check' when there is only one node per level. In this case, we + // can just ignore the id (and only focus on the label and terminal values). - // Compare their content to discern whether there exists an isomorphism - // between them. + // Compare their content to discern whether there exists an isomorphism between them. if (f0->is_canonical() && f1->is_canonical() && negate0 == negate1) { #ifdef ADIAR_STATS stats_equality.fast_check.runs += 1u; @@ -285,6 +276,6 @@ namespace adiar::internal bool is_isomorphic(const exec_policy& ep, const dd& a, const dd& b) { - return is_isomorphic(ep, a.file, b.file, a.negate, b.negate); + return is_isomorphic(ep, a._file, b._file, a._negate, b._negate); } } diff --git a/src/adiar/internal/algorithms/pred.h b/src/adiar/internal/algorithms/pred.h index d793906ea..773f7b5fe 100644 --- a/src/adiar/internal/algorithms/pred.h +++ b/src/adiar/internal/algorithms/pred.h @@ -15,24 +15,23 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// Struct to hold statistics for equality checking extern statistics::equality_t stats_equality; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Compute whether two shared levelized node files (with associated /// negation flags) are isomorphic. /// - /// \details Checks whether the two files are isomorphic, i.e. whether there - /// is a structure-preserving mapping between `f0` and `f1`. This - /// assumes, that both files are of a unique reduced form. + /// \details Checks whether the two files are isomorphic, i.e. whether there is a + /// structure-preserving mapping between `f0` and `f1`. This assumes, that both files are + /// of a unique reduced form. /// /// \param fi The two files of nodes to compare. /// \param negatei Whether the nodes of fi should be read in negated form /// - /// \return Whether `f0` and `f1` have isomorphic DAGs when applying the given - /// negation flags. - ////////////////////////////////////////////////////////////////////////////// + /// \return Whether `f0` and `f1` have isomorphic DAGs when applying the given negation flags. + ////////////////////////////////////////////////////////////////////////////////////////////////// bool is_isomorphic(const exec_policy& ep, const shared_levelized_file& f0, @@ -40,23 +39,23 @@ namespace adiar::internal const bool negate0 = false, const bool negate1 = false); - ////////////////////////////////////////////////////////////////////////////// - /// \brief Computes whether two decision diagrams are isomorphic; i.e. whether - /// they are equivalent (under the same deletion-rule). + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Computes whether two decision diagrams are isomorphic; i.e. whether they are equivalent + /// (under the same deletion-rule). /// - /// \details Checks whether the two files are isomorphic, i.e. whether there - /// is a structure-preserving mapping between `f0` and `f1`. This - /// assumes, that both files are of a unique reduced form. + /// \details Checks whether the two files are isomorphic, i.e. whether there is a + /// structure-preserving mapping between `f0` and `f1`. This assumes, that both files are + /// of a unique reduced form. /// /// \param a The first decision diagram. /// \param b The second decision diagram. /// - /// \return Whether a and b have isomorphic DAGs. - ////////////////////////////////////////////////////////////////////////////// + /// \return Whether `a` and `b` have isomorphic DAGs. + ////////////////////////////////////////////////////////////////////////////////////////////////// bool is_isomorphic(const exec_policy& ep, const dd& a, const dd& b); - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// // Data structures template using pred_request = request<2, nodes_carried>; @@ -183,25 +182,24 @@ namespace adiar::internal return comp_policy::no_early_return_value; } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// Behaviour can be changed with the 'comp_policy'. /// /// - The 'resolve_terminals' function resolves the case of being given two terminals. /// - /// - The 'resolve_request' function checks for early termination and places - /// new recursion requests in the priority queue if more recursions are needed. + /// - The 'resolve_request' function checks for early termination and places new recursion + /// requests in the priority queue if more recursions are needed. /// - /// - If the constexpr 'request_capped_by_level_size' variable is set to true, - /// then the algorithm is guaranteed to only run in O(sort(N_1)) number of - /// I/Os. + /// - If the constexpr 'request_capped_by_level_size' variable is set to true, then the algorithm + /// is guaranteed to only run in O(sort(N_1)) number of I/Os. /// - /// - The constexpr 'early_return_value' and 'no_early_return_value' change the - /// return value on early returns. + /// - The constexpr 'early_return_value' and 'no_early_return_value' change the return value on + /// early returns. /// - /// This 'comp_policy' also should inherit (or provide) the general policy for - /// the decision_diagram used (i.e. bdd_policy in bdd/bdd.h, zdd_policy in - /// zdd/zdd.h and so on). This provides the following functions - ////////////////////////////////////////////////////////////////////////////// + /// This 'comp_policy' also should inherit (or provide) the general policy for the + /// decision_diagram used (i.e. bdd_policy in bdd/bdd.h, zdd_policy in zdd/zdd.h and so on). This + /// provides the following functions + ////////////////////////////////////////////////////////////////////////////////////////////////// template bool comparison_check(const exec_policy& ep, @@ -210,12 +208,11 @@ namespace adiar::internal const bool negate0, const bool negate1) { - // Compute amount of memory available for auxiliary data structures after - // having opened all streams. + // Compute amount of memory available for auxiliary data structures after having opened all + // streams. // - // We then may derive an upper bound on the size of auxiliary data - // structures and check whether we can run them with a faster internal - // memory variant. + // We then may derive an upper bound on the size of auxiliary data structures and check whether + // we can run them with a faster internal memory variant. const size_t aux_available_memory = memory_available() // Input - 2 * node_stream<>::memory_usage() @@ -294,7 +291,7 @@ namespace adiar::internal bool comparison_check(const exec_policy& ep, const dd& a, const dd& b) { - return comparison_check(ep, a.file, b.file, a.negate, b.negate); + return comparison_check(ep, a._file, b._file, a._negate, b._negate); } } diff --git a/src/adiar/internal/algorithms/reduce.h b/src/adiar/internal/algorithms/reduce.h index e9b2d636b..e3bab411d 100644 --- a/src/adiar/internal/algorithms/reduce.h +++ b/src/adiar/internal/algorithms/reduce.h @@ -626,7 +626,7 @@ namespace adiar::internal // Is it already reduced? if (input.template has()) { return typename Policy::dd_type(input.template get(), - input.negate); + input._negate); } // Get unreduced input diff --git a/src/adiar/internal/algorithms/replace.h b/src/adiar/internal/algorithms/replace.h index 2fd13194c..484eca5dd 100644 --- a/src/adiar/internal/algorithms/replace.h +++ b/src/adiar/internal/algorithms/replace.h @@ -245,7 +245,7 @@ namespace adiar::internal if constexpr (check_reduced) { if (__dd.template has()) { const typename Policy::dd_type dd( - __dd.template get(), __dd.negate); + __dd.template get(), __dd._negate); return replace(ep, dd, m, m_type); } } @@ -294,7 +294,7 @@ namespace adiar::internal // Is it already reduced? if (__dd.template has()) { const typename Policy::dd_type dd(__dd.template get(), - __dd.negate); + __dd._negate); return replace(ep, dd, m); } diff --git a/src/adiar/internal/data_structures/level_merger.h b/src/adiar/internal/data_structures/level_merger.h index 9a2879320..34333d543 100644 --- a/src/adiar/internal/data_structures/level_merger.h +++ b/src/adiar/internal/data_structures/level_merger.h @@ -13,10 +13,10 @@ namespace adiar::internal { // TODO (code clarity): - // Add to 'File' an enum with 'Ascending'/'Descending' to then derive the - // comparator in conjunction with 'Reverse'. + // Add to 'File' an enum with 'Ascending'/'Descending' to then derive the comparator in + // conjunction with 'Reverse'. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Merges the levels from one or more files. /// /// \tparam File Type of the files to read from. @@ -24,7 +24,7 @@ namespace adiar::internal /// \tparam Comp Comparator with which to merge the levels. /// /// \tparam FileCount Number of files to read from. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class level_merger { @@ -47,9 +47,9 @@ namespace adiar::internal unique_ptr _level_streams[FileCount]; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach onto the given list of files. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void hook(const File (&fs)[FileCount]) { @@ -58,20 +58,20 @@ namespace adiar::internal } } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach onto the given list of decision diagrams. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void hook(const dd (&dds)[FileCount]) { for (size_t idx = 0u; idx < FileCount; idx++) { - _level_streams[idx] = adiar::make_unique(dds[idx].file); + _level_streams[idx] = adiar::make_unique(dds[idx]._file); } } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach onto the given list of (unreduced) decision diagrams. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void hook(const __dd (&dds)[FileCount]) { @@ -80,9 +80,9 @@ namespace adiar::internal } } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether there are more levels to fetch. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool can_pull() { @@ -92,11 +92,11 @@ namespace adiar::internal return false; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the next level. /// /// \pre `can_pull() == true` - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_type peek() { @@ -115,11 +115,11 @@ namespace adiar::internal return min_level; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the next level and go to the next. /// /// \pre `can_pull() == true` - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_type pull() { diff --git a/src/adiar/internal/dd.h b/src/adiar/internal/dd.h index d11682ce3..406b2b122 100644 --- a/src/adiar/internal/dd.h +++ b/src/adiar/internal/dd.h @@ -21,105 +21,101 @@ namespace adiar::internal class dd; - ////////////////////////////////////////////////////////////////////////////// - /// A std::variant is used to distinguish the type of file. This uses - /// std::monostate to hold a 'nothing' value, i.e. when there is no file. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// A std::variant is used to distinguish the type of file. This uses std::monostate to hold a + /// 'nothing' value, i.e. when there is no file. + ////////////////////////////////////////////////////////////////////////////////////////////////// using no_file = std::monostate; - ////////////////////////////////////////////////////////////////////////////// - /// \warning You should never explicitly be dealing with this class or have it - /// be an l-value. Implicit conversion from an unreduced to the reduced type - /// will call the correct reduce algorithm. + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \warning You should never explicitly be dealing with this class or have it be an l-value. + /// Implicit conversion from an unreduced to the reduced type will call the correct reduce + /// algorithm. /// - /// An algorithm may return a node-based decision diagram in a - /// `shared_levelized_file` or a yet to-be reduced decision diagram in - /// in an `shared_levelized_file`. So, we use a `std::variant` to hold - /// the `shared_levelized_file` or `shared_levelized_file` without - /// having to pay for the expensive constructors and use a lot of space. + /// An algorithm may return a node-based decision diagram in a `shared_levelized_file` or a + /// yet to-be reduced decision diagram in in an `shared_levelized_file`. So, we use a + /// `std::variant` to hold the `shared_levelized_file` or `shared_levelized_file` + /// without having to pay for the expensive constructors and use a lot of space. /// - /// A third possiblity is for it to contain a `std::monostate`, i.e. - /// `no_file`, such that an algorithm can return 'null' in some specific - /// places. In most cases, this should be ignored and will otherwise lead to - /// exceptions. - ////////////////////////////////////////////////////////////////////////////// + /// A third possiblity is for it to contain a `std::monostate`, i.e. `no_file`, such that an + /// algorithm can return 'null' in some specific places. In most cases, this should be ignored and + /// will otherwise lead to exceptions. + ////////////////////////////////////////////////////////////////////////////////////////////////// class __dd { public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of nodes of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using node_type = node; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file object node-based representation of a diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using shared_node_file_type = shared_levelized_file; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of nodes of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using arc_type = arc; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file object arc-based representation of a diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using shared_arc_file_type = shared_levelized_file; - //////////////////////////////////////////////////////////////////////////// - /// \brief Union of levelized node or arc files to reflect the possible - /// return types of a function and a 'no_file' for 'error'. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Union of levelized node or arc files to reflect the possible return types of a + /// function and a 'no_file' for 'error'. + //////////////////////////////////////////////////////////////////////////////////////////////// std::variant _union; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Propagation of the `dd.negate` flag. - /// - /// TODO: prefix with '_' - //////////////////////////////////////////////////////////////////////////// - bool negate = false; + //////////////////////////////////////////////////////////////////////////////////////////////// + bool _negate = false; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Copy of the execution policy given to the top-down algorithm. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// exec_policy _policy; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Constructors - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Default construction to \em nothing. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// __dd() = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Conversion for algorithms returning already-reduced nodes. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// __dd(const shared_node_file_type& f) : _union(f) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Conversion for algorithms returning to-be reduced arcs - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// __dd(const shared_arc_file_type& f, const exec_policy& ep) : _union(f) , _policy(ep) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Conversion from a decision diagram (such that it can be passed /// along). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// __dd(const dd& dd); - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Accessors // TODO: change from 'file_t' to 'file::value_type'. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the union currently holds a certain file type. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template bool has() const @@ -127,11 +123,11 @@ namespace adiar::internal return std::holds_alternative(_union); } - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Get the content of a certain type. /// /// \pre `has() == true` - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template const file_t& get() const @@ -139,11 +135,11 @@ namespace adiar::internal return std::get(_union); } - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether it currently holds no content. /// /// \details The end user should not see this in the end. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool empty() const { @@ -153,9 +149,9 @@ namespace adiar::internal // TODO (optimisation): // Add precondition to be with 'arcs' only? - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of nodes. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size() const { @@ -167,12 +163,12 @@ namespace adiar::internal return 0u; } - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the 1-level cut of the desired type, i.e. of the sub-graph - /// including the desired type of arcs. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the 1-level cut of the desired type, i.e. of the sub-graph including the + /// desired type of arcs. /// /// \param ct The type of the cut to obtain - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// cut::size_type max_1level_cut(const cut ct) const { @@ -185,12 +181,12 @@ namespace adiar::internal return 0u; } - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the 2-level cut of the desired type, i.e. of the sub-graph - /// including the desired type of arcs. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the 2-level cut of the desired type, i.e. of the sub-graph including the + /// desired type of arcs. /// /// \param ct The type of the cut to obtain - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// cut::size_type max_2level_cut(const cut ct) const { @@ -206,24 +202,24 @@ namespace adiar::internal return 0u; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of terminals of a certain value. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t number_of_terminals(const bool value) const { if (has()) { - return get()->number_of_terminals[negate ^ value]; + return get()->number_of_terminals[this->_negate ^ value]; } if (has()) { - return get()->number_of_terminals[negate ^ value]; + return get()->number_of_terminals[this->_negate ^ value]; } return 0u; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of terminals. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t number_of_terminals() const { @@ -239,227 +235,226 @@ namespace adiar::internal } }; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Container for the files that represent a Decision Diagram. /// - /// \remark To ensure the most disk-space is available, try to garbage collect - /// objects of this type as quickly as possible and/or minimise the - /// number of lvalues of this type. - ////////////////////////////////////////////////////////////////////////////// + /// \remark To ensure the most disk-space is available, try to garbage collect objects of this + /// type as quickly as possible and/or minimise the number of lvalues of this type. + ////////////////////////////////////////////////////////////////////////////////////////////////// class dd { - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Constants public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of nodes of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using node_type = node; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of pointers of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using pointer_type = node_type::pointer_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of this node's variable label. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using label_type = node_type::label_type; - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The maximal possible value for a unique identifier's label. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static constexpr label_type max_label = node_type::max_label; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of this node's level identifier. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using id_type = node_type::id_type; - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The maximal possible value for this nodes level identifier. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static constexpr id_type max_id = node_type::max_id; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of a terminal value. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using terminal_type = typename node_type::terminal_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief File type for the file object representing the diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using node_file_type = levelized_file; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief File type for the shared file object representing the diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using shared_node_file_type = shared_file_ptr; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Internal state protected: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The file describing the actual DAG of the decision diagram. - //////////////////////////////////////////////////////////////////////////// - shared_node_file_type file; - - //////////////////////////////////////////////////////////////////////////// - /// \brief Release the claim on the underlying file, thereby decreasing its - /// reference counter. If this is the sole owner of that file object, - /// then that object is destructed together with the physical files - /// on disk (if temporary). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + shared_node_file_type _file; + + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Release the claim on the underlying file, thereby decreasing its reference counter. + /// If this is the sole owner of that file object, then that object is destructed + /// together with the physical files on disk (if temporary). + //////////////////////////////////////////////////////////////////////////////////////////////// void deref() { - file.reset(); + this->_file.reset(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether to negate the leaves when reading nodes from the file. - //////////////////////////////////////////////////////////////////////////// - bool negate = false; // TODO: move to 'bdd' or generalize to 'attribute'? + // + // TODO: move to 'bdd' or generalize to 'attribute'? + //////////////////////////////////////////////////////////////////////////////////////////////// + bool _negate = false; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Constructors public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Constructor to wrap the node-based result of an algorithm. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// dd(const shared_node_file_type& f, bool negate = false) - : file(f) - , negate(negate) + : _file(f) + , _negate(negate) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Copy construction, incrementing the reference count on the file /// underneath. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// dd(const dd& dd) - : file(dd.file) - , negate(dd.negate) + : _file(dd._file) + , _negate(dd._negate) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Move construction, taking over ownership of the files underneath. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// dd(dd&& dd) - : file(std::move(dd.file)) - , negate(std::move(dd.negate)) + : _file(std::move(dd._file)) + , _negate(std::move(dd._negate)) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // NOTE: // - // To implement the specific DD, add the following move-conversion that - // runs the Reduce algorithm. + // To implement the specific DD, add the following move-conversion that runs the Reduce + // algorithm. // // dd(__dd &&dd) - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Read-only access to the negation flag. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool is_negated() const { - return negate; + return this->_negate; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Read-only access to the raw files and meta information. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const shared_node_file_type file_ptr() const { - return file; + return this->_file; } - //////////////////////////////////////////////////////////////////////////// - /// \brief Read-only access to the members of the raw files and meta - /// information, i.e. this is similar to writing - /// `.file_ptr()->`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Read-only access to the members of the raw files and meta information, i.e. this is + /// similar to writing `.file_ptr()->`. + //////////////////////////////////////////////////////////////////////////////////////////////// const node_file_type* operator->() const { - return file_ptr().get(); + return this->_file.get(); } /// \cond - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the 1-level cut of the desired type, i.e. of the sub-graph - /// including the desired type of arcs. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the 1-level cut of the desired type, i.e. of the sub-graph including the + /// desired type of arcs. /// /// \param ct The type of the cut to obtain - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// cut::size_type max_1level_cut(const cut ct) const { - return file->max_1level_cut[negate_cut_type(ct)]; + return this->_file->max_1level_cut[negate_cut_type(ct)]; } - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the 2-level cut of the desired type, i.e. of the sub-graph - /// including the desired type of arcs. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the 2-level cut of the desired type, i.e. of the sub-graph including the + /// desired type of arcs. /// /// \param ct The type of the cut to obtain - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// cut::size_type max_2level_cut(const cut ct) const { - return file->max_2level_cut[negate_cut_type(ct)]; + return this->_file->max_2level_cut[negate_cut_type(ct)]; } /// \endcond - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The number of elements in the node file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size() const { - return file->size(); + return this->_file->size(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The number of nodes on the widest level. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t width() const { - return file->width; + return this->_file->width; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of terminals of a certain value. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t number_of_terminals(const bool value) const { - return file->number_of_terminals[negate ^ value]; + return this->_file->number_of_terminals[this->_negate ^ value]; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of terminals. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t number_of_terminals() const { - return number_of_terminals(false) + number_of_terminals(true); + return this->number_of_terminals(false) + this->number_of_terminals(true); } private: - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the cut-type that matches with the current state of the /// negation flag. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// cut negate_cut_type(const cut ct) const { - if (!negate) { return ct; } + if (!this->_negate) { return ct; } switch (ct) { case cut::Internal_False: return cut::Internal_True; @@ -468,7 +463,7 @@ namespace adiar::internal } } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Friends // |- streaming classes friend class __dd; @@ -512,95 +507,94 @@ namespace adiar::internal }; inline __dd::__dd(const dd& dd) - : _union(dd.file) - , negate(dd.negate) + : _union(dd._file) + , _negate(dd._negate) {} /// \cond template class dd_policy { - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// Constants public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the class representing the \em reduced decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using dd_type = DD; - //////////////////////////////////////////////////////////////////////////// - /// \brief Type of the class representing the \em possibly \em unreduced - /// decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type of the class representing the \em possibly \em unreduced decision diagram. + //////////////////////////////////////////////////////////////////////////////////////////////// using __dd_type = __DD; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of nodes of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using node_type = typename dd_type::node_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of pointers of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using pointer_type = typename dd_type::pointer_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of pointers of this diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using children_type = typename node_type::children_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of this node's variable label. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using label_type = typename dd_type::label_type; - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The maximal possible value for a unique identifier's label. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static constexpr label_type max_label = dd_type::max_label; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of this node's level identifier. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using id_type = typename dd_type::id_type; - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The maximal possible value for this nodes level identifier. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static constexpr id_type max_id = dd_type::max_id; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of a terminal value. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using terminal_type = typename dd_type::terminal_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of shared nodes for this diagram type. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using shared_node_file_type = typename __dd_type::shared_node_file_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of shared arcs for this diagram type. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using shared_arc_file_type = typename __dd_type::shared_arc_file_type; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// Function declaration public: - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Result of applying the suppression rule. /// /// \returns A pointer to the node itself or one of its children. - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static inline pointer_type reduction_rule(const node_type& n); - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Provides the children of a node that was suppressed. /// - /// \details This is the inverse of `reduction_rule`; to fully reconstruct the - /// node, add the variable label next to these children. - ////////////////////////////////////////////////////////////////////////////// + /// \details This is the inverse of `reduction_rule`; to fully reconstruct the node, add the + /// variable label next to these children. + //////////////////////////////////////////////////////////////////////////////////////////////// static inline children_type reduction_rule_inv(const pointer_type& child); }; diff --git a/src/adiar/internal/dd_func.h b/src/adiar/internal/dd_func.h index 160fa9e51..094670d3d 100644 --- a/src/adiar/internal/dd_func.h +++ b/src/adiar/internal/dd_func.h @@ -23,9 +23,9 @@ namespace adiar::internal return dd->is_canonical(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether a given decision diagram represents a terminal. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template bool dd_isterminal(const DD& dd) @@ -34,20 +34,20 @@ namespace adiar::internal return dd->is_terminal(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the terminal's value (if 'is_terminal' is true). - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template bool dd_valueof(const DD& dd) { // TODO: Move into 'dd' class... - return dd.negate ^ dd->value(); + return dd._negate ^ dd->value(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether a given decision diagram represents the false terminal. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template bool dd_isfalse(const DD& dd) @@ -56,9 +56,9 @@ namespace adiar::internal return dd_isterminal(dd) && !dd_valueof(dd); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether a given decision diagram represents the true terminal. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template bool dd_istrue(const DD& dd) @@ -67,11 +67,11 @@ namespace adiar::internal return dd_isterminal(dd) && dd_valueof(dd); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Get the root's variable label. /// /// \throws invalid_argument If `dd` is a terminal. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template dd::label_type dd_topvar(const DD& dd) @@ -81,25 +81,25 @@ namespace adiar::internal return dd->first_level(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Get the minimal occurring label in the decision diagram. /// /// \throws invalid_argument If `dd` is a terminal. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template dd::label_type dd_minvar(const DD& dd) { - // TODO: Custom implementation with an O(L) scan when variable order is not - // certain to be the default ascending one. + // TODO: Custom implementation with an O(L) scan when variable order is not certain to be the + // default ascending one. return dd_topvar(dd); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Get the maximal occurring label in the decision diagram. /// /// \throws invalid_argument If `dd` is a terminal. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template dd::label_type dd_maxvar(const DD& dd) @@ -111,9 +111,9 @@ namespace adiar::internal return dd->last_level(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of nodes in a decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template size_t dd_nodecount(const DD& dd) @@ -121,9 +121,9 @@ namespace adiar::internal return dd_isterminal(dd) ? 0u : dd->size(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of variables, i.e. levels, present in a decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template typename DD::label_type dd_varcount(const DD& dd) @@ -131,9 +131,9 @@ namespace adiar::internal return dd->levels(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of nodes on the widest level of a decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template size_t dd_width(const DD& dd) @@ -141,10 +141,9 @@ namespace adiar::internal return dd.width(); } - //////////////////////////////////////////////////////////////////////////// - /// \brief The variable labels (in order of their level) that are present in a - /// decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief The variable labels (in order of their level) that are present in a decision diagram. + //////////////////////////////////////////////////////////////////////////////////////////////// template void dd_support(const DD& dd, const consumer& cb) diff --git a/src/adiar/internal/io/levelized_file_stream.h b/src/adiar/internal/io/levelized_file_stream.h index 05a4abf15..ce694ddf6 100644 --- a/src/adiar/internal/io/levelized_file_stream.h +++ b/src/adiar/internal/io/levelized_file_stream.h @@ -16,18 +16,17 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief File stream of levelized files. /// /// \param T The type of the file(s)'s elements /// /// \param Reverse Whether the reading direction should be reversed /// - /// \remark Since the content of all levelized files are generated in Reverse - /// of the desired reading order, then 'reversing' the reversed input - /// is equivalent to not reversing the underlying stream. Hence, we do - /// hide a negation of the \em Reverse parameter. - ////////////////////////////////////////////////////////////////////////////// + /// \remark Since the content of all levelized files are generated in Reverse of the desired + /// reading order, then 'reversing' the reversed input is equivalent to not reversing the + /// underlying stream. Hence, we do hide a negation of the \em Reverse parameter. + ////////////////////////////////////////////////////////////////////////////////////////////////// template class levelized_file_stream { @@ -47,44 +46,44 @@ namespace adiar::internal file_stream _streams[streams]; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create unattached to any file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_stream() {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_stream(const levelized_file_stream&) = delete; levelized_file_stream(levelized_file_stream&&) = delete; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_stream(const levelized_file& lf, const bool negate = false) { attach(lf, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_stream(const shared_ptr>& lf, const bool negate = false) { attach(lf, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches and cleans up when destructed. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// ~levelized_file_stream() = default; // <-- detach is within 'file_stream'. public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a levelized file. /// /// \pre No `levelized_file_writer` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const levelized_file& f, const bool negate = false) { @@ -94,11 +93,11 @@ namespace adiar::internal _streams[s_idx].attach(f._files[s_idx], nullptr, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a shared levelized file. /// /// \pre No `levelized_file_writer` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const shared_ptr>& f, const bool negate = false) { @@ -108,9 +107,9 @@ namespace adiar::internal _streams[s_idx].attach(f->_files[s_idx], f, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether this stream is attached to a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool attached() const { @@ -124,28 +123,27 @@ namespace adiar::internal return res; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches the stream from a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void detach() { for (size_t s_idx = 0; s_idx < streams; s_idx++) _streams[s_idx].detach(); } - //////////////////////////////////////////////////////////////////////////// - /// \brief Reset the read heads back to the beginning (relatively to the - /// reading direction). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Reset the read heads back to the beginning (relatively to the reading direction). + //////////////////////////////////////////////////////////////////////////////////////////////// void reset() { for (size_t s_idx = 0; s_idx < streams; s_idx++) _streams[s_idx].reset(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the sub-stream contains more elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template bool can_pull() const @@ -154,11 +152,11 @@ namespace adiar::internal return _streams[s_idx].can_pull(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain next element from a sub-stream (and move its read head). /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template value_type pull() @@ -167,12 +165,12 @@ namespace adiar::internal return _streams[s_idx].pull(); } - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the next element from the specified sub-stream (but do not - /// move the read head). + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the next element from the specified sub-stream (but do not move the read + /// head). /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template value_type peek() @@ -182,83 +180,83 @@ namespace adiar::internal } }; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Stream to access per-level meta information. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class level_info_stream : public file_stream { using parent_t = file_stream; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct unattached to a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream() = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const level_info_stream&) = delete; level_info_stream(level_info_stream&&) = delete; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const file& f) { parent_t::attach(f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const adiar::shared_ptr>& f) { parent_t::attach(f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template level_info_stream(const levelized_file& lf) { attach(lf); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a shared levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template level_info_stream(const adiar::shared_ptr>& lf) { attach(lf); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a (reduced) decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const dd& diagram) { attach(diagram); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a (possibly unreduced) decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const __dd& diagram) { attach(diagram); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches and cleans up when destructed. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// ~level_info_stream() = default; // <-- detach in '~file()' public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template void attach(const levelized_file& lf) @@ -267,9 +265,9 @@ namespace adiar::internal parent_t::attach(lf._level_info_file, nullptr, false); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a shared levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template void attach(const adiar::shared_ptr>& lf) @@ -278,18 +276,18 @@ namespace adiar::internal parent_t::attach(lf->_level_info_file, lf, false); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a (reduced) decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const dd& diagram) { - attach(diagram.file); + attach(diagram._file); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a (possibly unreduced) decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const __dd& diagram) { @@ -298,9 +296,8 @@ namespace adiar::internal } else if (diagram.has<__dd::shared_node_file_type>()) { attach(diagram.get<__dd::shared_node_file_type>()); } else { - // We should never be in the case of hooking into a 'no_file'. That type - // should only be used internally within an algorithm and never escape - // into its output. + // We should never be in the case of hooking into a 'no_file'. That type should only be used + // internally within an algorithm and never escape into its output. adiar_unreachable(); // LCOV_EXCL_LINE } } diff --git a/src/adiar/internal/io/node_arc_random_access.h b/src/adiar/internal/io/node_arc_random_access.h index 1a2b9e2c3..91ad756a9 100644 --- a/src/adiar/internal/io/node_arc_random_access.h +++ b/src/adiar/internal/io/node_arc_random_access.h @@ -57,7 +57,7 @@ namespace adiar::internal /// \pre The unreduced decision diagram is indexable. This is (almost) always the case. //////////////////////////////////////////////////////////////////////////////////////////////// node_arc_random_access(const __dd& diagram) - : node_arc_random_access(diagram.template get<__dd::shared_arc_file_type>(), diagram.negate) + : node_arc_random_access(diagram.template get<__dd::shared_arc_file_type>(), diagram._negate) { // adiar_assert(diagram->indexable); } diff --git a/src/adiar/internal/io/node_arc_stream.h b/src/adiar/internal/io/node_arc_stream.h index a09bb163e..d0a1b6c26 100644 --- a/src/adiar/internal/io/node_arc_stream.h +++ b/src/adiar/internal/io/node_arc_stream.h @@ -87,7 +87,7 @@ namespace adiar::internal : _stream(/*need to sort before attach*/) { adiar_assert(diagram.template has<__dd::shared_arc_file_type>()); - attach(diagram.template get<__dd::shared_arc_file_type>(), diagram.negate); + attach(diagram.template get<__dd::shared_arc_file_type>(), diagram._negate); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/io/node_stream.h b/src/adiar/internal/io/node_stream.h index 64c9c803d..5ea437440 100644 --- a/src/adiar/internal/io/node_stream.h +++ b/src/adiar/internal/io/node_stream.h @@ -8,88 +8,88 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Stream of nodes from a node file. /// - /// \param Reverse Whether the reading direction should be Reversed - /// (relatively to the ordering of nodes within the file). + /// \param Reverse Whether the reading direction should be Reversed (relatively to the ordering of + /// nodes within the file). /// /// \see shared_levelized_file - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class node_stream : public levelized_file_stream { using parent_t = levelized_file_stream; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create unattached to any file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// node_stream() = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const node_stream&) = delete; node_stream(node_stream&&) = delete; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a node file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const levelized_file& file, const bool negate = false) : parent_t(file, negate) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared node file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const shared_ptr>& file, const bool negate = false) : parent_t(file, negate) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a Decision Diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const dd& diagram) - : parent_t(diagram.file, diagram.negate) + : parent_t(diagram._file, diagram._negate) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the stream contains more elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool can_pull() const { return parent_t::template can_pull<0>(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain next element (and move the read head). /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const node pull() { return parent_t::template pull<0>(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the next element (but do not move the read head). /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const node peek() { return parent_t::template peek<0>(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the first node "greater than" or "equal" the seeked uid. /// /// \param u Unique Identifier to seek for. /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const node seek(const node::uid_type& u) { diff --git a/src/adiar/zdd/pred.cpp b/src/adiar/zdd/pred.cpp index 6bf0f1fb7..03dcf2d95 100644 --- a/src/adiar/zdd/pred.cpp +++ b/src/adiar/zdd/pred.cpp @@ -46,8 +46,7 @@ namespace adiar bool zdd_ispoint(const zdd& A) { - // Assuming the ZDD is fully reduced (which it should be), then it can only - // be a point if: + // Assuming the ZDD is fully reduced (which it should be), then it can only be a point if: // // 1. Its width is exactly 1 (but also allow 0 for the terminal cases) // @@ -79,7 +78,7 @@ namespace adiar return zdd_unequal(exec_policy(), A, B); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class ignore_levels { @@ -174,9 +173,8 @@ namespace adiar static bool resolve_request(pq_1_t& pq, const internal::tuple& rp) { - // Are they both a terminal? If so, check whether the left-hand side is true - // and not the right, which would contradict being an implication (i.e. - // representing a subset). + // Are they both a terminal? If so, check whether the left-hand side is true and not the + // right, which would contradict being an implication (i.e. representing a subset). if (rp[0].is_terminal() && rp[1].is_terminal()) { return essential(rp[0]) > essential(rp[1]); } @@ -200,7 +198,7 @@ namespace adiar bool zdd_subseteq(const exec_policy& ep, const zdd& A, const zdd& B) { - if (A.file == B.file) { return true; } + if (A._file == B._file) { return true; } return internal::comparison_check(ep, A, B); } @@ -211,7 +209,7 @@ namespace adiar return zdd_subseteq(exec_policy(), A, B); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// bool zdd_subset(const exec_policy& ep, const zdd& A, const zdd& B) { @@ -224,7 +222,7 @@ namespace adiar return zdd_subset(exec_policy(), A, B); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// class zdd_disjoint_policy : public zdd_policy , public internal::prod2_mixed_level_merger @@ -283,7 +281,7 @@ namespace adiar bool zdd_disjoint(const exec_policy& ep, const zdd& A, const zdd& B) { - if (A.file == B.file) { return zdd_isfalse(A); } + if (A._file == B._file) { return zdd_isfalse(A); } return internal::comparison_check(ep, A, B); } diff --git a/src/adiar/zdd/zdd.cpp b/src/adiar/zdd/zdd.cpp index bab9075e0..ec6403c0f 100644 --- a/src/adiar/zdd/zdd.cpp +++ b/src/adiar/zdd/zdd.cpp @@ -87,8 +87,8 @@ namespace adiar zdd& zdd::operator=(const zdd& other) { - this->negate = other.negate; - this->file = other.file; + this->_negate = other._negate; + this->_file = other._file; return *this; } diff --git a/src/adiar/zdd/zdd.h b/src/adiar/zdd/zdd.h index 7907eae4d..b589942d3 100644 --- a/src/adiar/zdd/zdd.h +++ b/src/adiar/zdd/zdd.h @@ -150,7 +150,7 @@ namespace adiar internal::cut::size_type max_1level_cut(const internal::cut ct) const { - return add_false_cofactor(ct, file->max_1level_cut); + return add_false_cofactor(ct, this->_file->max_1level_cut); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -162,7 +162,7 @@ namespace adiar internal::cut::size_type max_2level_cut(const internal::cut ct) const { - return add_false_cofactor(ct, file->max_2level_cut); + return add_false_cofactor(ct, this->_file->max_2level_cut); } /// \endcond diff --git a/test/adiar/bdd/test_apply.cpp b/test/adiar/bdd/test_apply.cpp index 5353fcf4e..8e84c2b3f 100644 --- a/test/adiar/bdd/test_apply.cpp +++ b/test/adiar/bdd/test_apply.cpp @@ -404,7 +404,7 @@ go_bandit([]() { __bdd out = bdd_and(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should shortcut F /\\ x0", [&]() { @@ -465,7 +465,7 @@ go_bandit([]() { __bdd out = bdd_and(bdd_1, bdd_1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); }); @@ -474,14 +474,14 @@ go_bandit([]() { __bdd out = bdd_nand(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); it("should shortcut on negating on x0 and T", [&]() { __bdd out = bdd_nand(bdd_T, bdd_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); it("should collapse on the same BDD twice, where one is negated", [&]() { @@ -576,14 +576,14 @@ go_bandit([]() { __bdd out = bdd_or(bdd_x0, bdd_F); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should OR shortcut on irrelevance F \\/ x0", [&]() { __bdd out = bdd_or(bdd_F, bdd_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should shortcut [1] \\/ T", [&]() { @@ -727,14 +727,14 @@ go_bandit([]() { __bdd out = bdd_xor(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); it("should shortcut on negating on T ^ x0", [&]() { __bdd out = bdd_xor(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); it("should collapse on the same BDD twice", [&]() { @@ -875,7 +875,7 @@ go_bandit([]() { __bdd out = bdd_imp(bdd_T, bdd_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should shortcut F -> [1]", [&]() { @@ -910,7 +910,7 @@ go_bandit([]() { __bdd out = bdd_imp(bdd_not(bdd_2), bdd_2); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_2)); - AssertThat(out.negate, + AssertThat(out._negate, Is().False()); // negated the already negated input doubly-negating }); @@ -918,7 +918,7 @@ go_bandit([]() { __bdd out = bdd_imp(bdd_2, bdd_not(bdd_2)); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_2)); - AssertThat(out.negate, Is().True()); // negated the first of the two + AssertThat(out._negate, Is().True()); // negated the first of the two }); }); }); diff --git a/test/adiar/bdd/test_bdd.cpp b/test/adiar/bdd/test_bdd.cpp index fa205cce5..2e636c7c7 100644 --- a/test/adiar/bdd/test_bdd.cpp +++ b/test/adiar/bdd/test_bdd.cpp @@ -52,14 +52,14 @@ go_bandit([]() { __bdd t1 = bdd(x0_and_x1); AssertThat(t1.has>(), Is().True()); AssertThat(t1.get<__bdd::shared_node_file_type>(), Is().EqualTo(x0_and_x1_nf)); - AssertThat(t1.negate, Is().False()); + AssertThat(t1._negate, Is().False()); }); it("should copy-construct values from negated bdd", [&]() { __bdd t2 = bdd(x0_nand_x1); AssertThat(t2.has>(), Is().True()); AssertThat(t2.get<__bdd::shared_node_file_type>(), Is().EqualTo(x0_and_x1_nf)); - AssertThat(t2.negate, Is().True()); + AssertThat(t2._negate, Is().True()); }); it("should copy-construct values from __bdd", [&]() { @@ -67,14 +67,14 @@ go_bandit([]() { __bdd t2 = t1; AssertThat(t2.has>(), Is().True()); AssertThat(t2.get<__bdd::shared_node_file_type>(), Is().EqualTo(x0_and_x1_nf)); - AssertThat(t2.negate, Is().False()); + AssertThat(t2._negate, Is().False()); }); it("should copy-construct values from shared_levelized_file", [&]() { __bdd t1 = x0_and_x1; AssertThat(t1.has>(), Is().True()); AssertThat(t1.get<__bdd::shared_node_file_type>(), Is().EqualTo(x0_and_x1_nf)); - AssertThat(t1.negate, Is().False()); + AssertThat(t1._negate, Is().False()); }); shared_levelized_file af; @@ -97,7 +97,7 @@ go_bandit([]() { __bdd t1(af, exec_policy::memory::Internal); AssertThat(t1.has>(), Is().True()); AssertThat(t1.get<__bdd::shared_arc_file_type>(), Is().EqualTo(af)); - AssertThat(t1.negate, Is().False()); + AssertThat(t1._negate, Is().False()); AssertThat(t1._policy, Is().EqualTo(exec_policy(exec_policy::memory::Internal))); }); diff --git a/test/adiar/bdd/test_if_then_else.cpp b/test/adiar/bdd/test_if_then_else.cpp index 0d823dbf4..7b91fcb97 100644 --- a/test/adiar/bdd/test_if_then_else.cpp +++ b/test/adiar/bdd/test_if_then_else.cpp @@ -253,7 +253,7 @@ go_bandit([]() { __bdd out = bdd_ite(bdd_T, bdd_x0, bdd_x1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should give back first file with negation flag on if-true (true ? ~x0 : (~x0))", [&]() { @@ -262,14 +262,14 @@ go_bandit([]() { __bdd out = bdd_ite(bdd_T, bdd_not(bdd_x0), bdd_not_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); it("should give back second file on if-false (false ? x0 : x1)", [&]() { __bdd out = bdd_ite(bdd_F, bdd_x0, bdd_x1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should give back second file on if-false (false ? (~x1) : ~x1)", [&]() { @@ -278,7 +278,7 @@ go_bandit([]() { __bdd out = bdd_ite(bdd_F, bdd_not_x1, bdd_not(bdd_x1)); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); // Trivial inputs with duplicate file inputs @@ -286,14 +286,14 @@ go_bandit([]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_x1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("should return 'then' file if 'else' file is the same [2]", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_not(bdd_x1), bdd_not(bdd_x1)); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); - AssertThat(out.negate, Is().True()); + AssertThat(out._negate, Is().True()); }); }); diff --git a/test/adiar/bdd/test_quantify.cpp b/test/adiar/bdd/test_quantify.cpp index 549b17504..cf8cb8399 100644 --- a/test/adiar/bdd/test_quantify.cpp +++ b/test/adiar/bdd/test_quantify.cpp @@ -1009,14 +1009,14 @@ go_bandit([]() { __bdd out = bdd_exists(in, 42); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(terminal_T)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("quantifies F terminal-only BDD as itself [&&]", [&]() { __bdd out = bdd_exists(bdd(terminal_F), 21); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(terminal_F)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); describe("access mode: random access", [&]() { @@ -1027,7 +1027,7 @@ go_bandit([]() { __bdd out = bdd_exists(ep, in, 42); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("shortcuts quantification of root into T terminal [&&]", [&]() { @@ -1673,7 +1673,7 @@ go_bandit([]() { __bdd out = bdd_exists(ep, in, 42); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("shortcuts quantification of root into T terminal [&&]", [&]() { @@ -7142,14 +7142,14 @@ go_bandit([]() { __bdd out = bdd_forall(in, 42); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(terminal_T)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("quantifies F terminal-only BDD as itself [&&]", [&]() { __bdd out = bdd_forall(bdd(terminal_F), 21); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(terminal_F)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); describe("access mode: random access", [&]() { diff --git a/test/adiar/bdd/test_restrict.cpp b/test/adiar/bdd/test_restrict.cpp index 26bc35d0f..6e8011b78 100644 --- a/test/adiar/bdd/test_restrict.cpp +++ b/test/adiar/bdd/test_restrict.cpp @@ -438,7 +438,7 @@ go_bandit([]() { __bdd out = bdd_restrict(bdd_T, ass.begin(), ass.end()); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_T)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("returns input unchanged when given a F terminal", [&]() { @@ -449,7 +449,7 @@ go_bandit([]() { __bdd out = bdd_restrict(bdd_F, ass.begin(), ass.end()); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_F)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("returns input unchanged when given an empty assignment", [&]() { @@ -458,7 +458,7 @@ go_bandit([]() { __bdd out = bdd_restrict(bdd_1, ass.begin(), ass.end()); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("returns input unchanged if assignment is disjoint of its variables", [&]() { @@ -469,7 +469,7 @@ go_bandit([]() { __bdd out = bdd_restrict(bdd_1, ass.begin(), ass.end()); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("sorts restricted terminal arc in BDD 4 for (_,F,T,_)", [&]() { @@ -905,14 +905,14 @@ go_bandit([]() { __bdd out = bdd_restrict(bdd_T, 42, true); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_T)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("returns input unchanged when given a F terminal", [&]() { __bdd out = bdd_restrict(bdd_F, 8, false); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_F)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("returns input unchanged if variable does not exist", [&]() { @@ -923,7 +923,7 @@ go_bandit([]() { __bdd out = bdd_restrict(bdd_1, 4, true); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("sorts restricted terminal arcs in BDD 3", [&]() { diff --git a/test/adiar/zdd/test_complement.cpp b/test/adiar/zdd/test_complement.cpp index b0dd91364..48bd2f7a2 100644 --- a/test/adiar/zdd/test_complement.cpp +++ b/test/adiar/zdd/test_complement.cpp @@ -48,14 +48,14 @@ go_bandit([]() { __zdd out = zdd_complement(zdd_F, dom_empty.begin(), dom_empty.end()); AssertThat(out.get>(), Is().EqualTo(zdd_F)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("produces { Ø } on { Ø } and U = Ø", [&]() { __zdd out = zdd_complement(zdd_F, dom_empty.begin(), dom_empty.end()); AssertThat(out.get>(), Is().EqualTo(zdd_F)); - AssertThat(out.negate, Is().False()); + AssertThat(out._negate, Is().False()); }); it("produces pow(U) on F terminal and U = { 0, 1, 2, 3 }", [&]() { diff --git a/test/adiar/zdd/test_zdd.cpp b/test/adiar/zdd/test_zdd.cpp index 06b7bb25e..1d41c7e55 100644 --- a/test/adiar/zdd/test_zdd.cpp +++ b/test/adiar/zdd/test_zdd.cpp @@ -50,7 +50,7 @@ go_bandit([]() { __zdd t1 = x0_or_x1; AssertThat(t1.has>(), Is().True()); AssertThat(t1.get>(), Is().EqualTo(x0_or_x1_nf)); - AssertThat(t1.negate, Is().False()); + AssertThat(t1._negate, Is().False()); }); it("copy-constructs values from __zdd", [&]() { @@ -58,14 +58,14 @@ go_bandit([]() { __zdd t2 = t1; AssertThat(t2.has>(), Is().True()); AssertThat(t2.get>(), Is().EqualTo(x0_or_x1_nf)); - AssertThat(t2.negate, Is().False()); + AssertThat(t2._negate, Is().False()); }); it("copy-constructs values from shared_levelized_file", [&]() { __zdd t1 = x0_or_x1; AssertThat(t1.has>(), Is().True()); AssertThat(t1.get>(), Is().EqualTo(x0_or_x1_nf)); - AssertThat(t1.negate, Is().False()); + AssertThat(t1._negate, Is().False()); }); __zdd::shared_arc_file_type af; @@ -88,7 +88,7 @@ go_bandit([]() { __zdd t1 = __zdd(af, exec_policy::access::Random_Access); AssertThat(t1.has<__zdd::shared_arc_file_type>(), Is().True()); AssertThat(t1.get<__zdd::shared_arc_file_type>(), Is().EqualTo(af)); - AssertThat(t1.negate, Is().False()); + AssertThat(t1._negate, Is().False()); AssertThat(t1._policy, Is().EqualTo(exec_policy(exec_policy::access::Random_Access))); }); diff --git a/test/test.h b/test/test.h index 4a6ab6226..c95ca0f2e 100644 --- a/test/test.h +++ b/test/test.h @@ -38,7 +38,7 @@ class node_test_stream : public node_stream {} node_test_stream(const __bdd& f) - : node_stream(f.get<__bdd::shared_node_file_type>(), f.negate) + : node_stream(f.get<__bdd::shared_node_file_type>(), f._negate) {} node_test_stream(const zdd& f) @@ -46,7 +46,7 @@ class node_test_stream : public node_stream {} node_test_stream(const __zdd& f) - : node_stream(f.get<__zdd::shared_node_file_type>(), f.negate) + : node_stream(f.get<__zdd::shared_node_file_type>(), f._negate) {} }; From 724d802911b72e3348c1218beca59d4451f928e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 09:02:18 +0200 Subject: [PATCH 02/30] Use public member functions rather than being friends of 'dd' class --- src/adiar/bdd/if_then_else.cpp | 12 +++--- src/adiar/internal/algorithms/convert.h | 2 +- src/adiar/internal/algorithms/pred.cpp | 2 +- src/adiar/internal/algorithms/pred.h | 3 +- .../internal/data_structures/level_merger.h | 2 +- src/adiar/internal/dd.h | 38 ------------------- src/adiar/internal/dd_func.h | 2 +- src/adiar/internal/io/levelized_file_stream.h | 2 +- src/adiar/internal/io/node_arc_stream.h | 8 ++-- src/adiar/internal/io/node_stream.h | 2 +- 10 files changed, 19 insertions(+), 54 deletions(-) diff --git a/src/adiar/bdd/if_then_else.cpp b/src/adiar/bdd/if_then_else.cpp index 1f4a97881..ba80a6164 100644 --- a/src/adiar/bdd/if_then_else.cpp +++ b/src/adiar/bdd/if_then_else.cpp @@ -517,13 +517,15 @@ namespace adiar // Package" of Karl S. Brace, Richard L. Rudell, and Randal E. Bryant. // Resolve being given the same underlying file in both cases - if (g._file == h._file) { return g._negate == h._negate ? __bdd(g) : bdd_xnor(f, g); } + if (g.file_ptr() == h.file_ptr()) { + return g.is_negated() == h.is_negated() ? __bdd(g) : bdd_xnor(f, g); + } // Resolve being given the same underlying file for conditional and a case - if (f._file == g._file) { - return f._negate == g._negate ? bdd_or(f, h) : bdd_and(bdd_not(f), h); - } else if (f._file == h._file) { - return f._negate == h._negate ? bdd_and(f, g) : bdd_imp(f, g); + if (f.file_ptr() == g.file_ptr()) { + return f.is_negated() == g.is_negated() ? bdd_or(f, h) : bdd_and(bdd_not(f), h); + } else if (f.file_ptr() == h.file_ptr()) { + return f.is_negated() == h.is_negated() ? bdd_and(f, g) : bdd_imp(f, g); } // Resolve being given a terminal in one of the cases diff --git a/src/adiar/internal/algorithms/convert.h b/src/adiar/internal/algorithms/convert.h index d2d303f38..57d84954c 100644 --- a/src/adiar/internal/algorithms/convert.h +++ b/src/adiar/internal/algorithms/convert.h @@ -47,7 +47,7 @@ namespace adiar::internal static typename to_policy::dd_type on_empty_labels(const typename from_policy::dd_type& dd) { - return typename to_policy::dd_type(dd._file, dd._negate); + return typename to_policy::dd_type(dd.file_ptr(), dd.is_negated()); } static typename to_policy::dd_type diff --git a/src/adiar/internal/algorithms/pred.cpp b/src/adiar/internal/algorithms/pred.cpp index fcaadb124..d519ba69e 100644 --- a/src/adiar/internal/algorithms/pred.cpp +++ b/src/adiar/internal/algorithms/pred.cpp @@ -276,6 +276,6 @@ namespace adiar::internal bool is_isomorphic(const exec_policy& ep, const dd& a, const dd& b) { - return is_isomorphic(ep, a._file, b._file, a._negate, b._negate); + return is_isomorphic(ep, a.file_ptr(), b.file_ptr(), a.is_negated(), b.is_negated()); } } diff --git a/src/adiar/internal/algorithms/pred.h b/src/adiar/internal/algorithms/pred.h index 773f7b5fe..c6bd61c6c 100644 --- a/src/adiar/internal/algorithms/pred.h +++ b/src/adiar/internal/algorithms/pred.h @@ -291,7 +291,8 @@ namespace adiar::internal bool comparison_check(const exec_policy& ep, const dd& a, const dd& b) { - return comparison_check(ep, a._file, b._file, a._negate, b._negate); + return comparison_check( + ep, a.file_ptr(), b.file_ptr(), a.is_negated(), b.is_negated()); } } diff --git a/src/adiar/internal/data_structures/level_merger.h b/src/adiar/internal/data_structures/level_merger.h index 34333d543..edcdd515b 100644 --- a/src/adiar/internal/data_structures/level_merger.h +++ b/src/adiar/internal/data_structures/level_merger.h @@ -65,7 +65,7 @@ namespace adiar::internal hook(const dd (&dds)[FileCount]) { for (size_t idx = 0u; idx < FileCount; idx++) { - _level_streams[idx] = adiar::make_unique(dds[idx]._file); + _level_streams[idx] = adiar::make_unique(dds[idx].file_ptr()); } } diff --git a/src/adiar/internal/dd.h b/src/adiar/internal/dd.h index 406b2b122..e07c3c417 100644 --- a/src/adiar/internal/dd.h +++ b/src/adiar/internal/dd.h @@ -465,45 +465,7 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// // Friends - // |- streaming classes friend class __dd; - - template - friend class level_info_stream; - - template - friend class node_stream; - - template - friend class level_merger; - - // |- algorithm functions and classes - friend bool - is_isomorphic(const exec_policy&, const dd&, const dd&); - - template - friend bool - comparison_check(const exec_policy&, const dd&, const dd&); - - template - friend class convert_dd_policy; - - // |- public API - template - friend bool - dd_isterminal(const dd_t& dd); - - template - friend bool - dd_valueof(const dd_t& dd); - - template - friend label_type - dd_minvar(const dd_t& dd); - - template - friend label_type - dd_maxvar(const dd_t& dd); }; inline __dd::__dd(const dd& dd) diff --git a/src/adiar/internal/dd_func.h b/src/adiar/internal/dd_func.h index 094670d3d..46bdb3169 100644 --- a/src/adiar/internal/dd_func.h +++ b/src/adiar/internal/dd_func.h @@ -42,7 +42,7 @@ namespace adiar::internal dd_valueof(const DD& dd) { // TODO: Move into 'dd' class... - return dd._negate ^ dd->value(); + return dd.is_negated() ^ dd->value(); } ////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/io/levelized_file_stream.h b/src/adiar/internal/io/levelized_file_stream.h index ce694ddf6..4faba6464 100644 --- a/src/adiar/internal/io/levelized_file_stream.h +++ b/src/adiar/internal/io/levelized_file_stream.h @@ -282,7 +282,7 @@ namespace adiar::internal void attach(const dd& diagram) { - attach(diagram._file); + attach(diagram.file_ptr()); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/io/node_arc_stream.h b/src/adiar/internal/io/node_arc_stream.h index d0a1b6c26..d7f7d8a13 100644 --- a/src/adiar/internal/io/node_arc_stream.h +++ b/src/adiar/internal/io/node_arc_stream.h @@ -11,14 +11,14 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Stream nodes from an arc file (skipping any of Reduce algorithm). /// - /// \param Reverse Whether the reading direction should be reversed - /// (relatively to the ordering of nodes within the file). + /// \param Reverse Whether the reading direction should be reversed (relatively to the ordering of + /// nodes within the file). /// /// \see shared_levelized_file - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class node_arc_stream : protected arc_stream { diff --git a/src/adiar/internal/io/node_stream.h b/src/adiar/internal/io/node_stream.h index 5ea437440..6241517ba 100644 --- a/src/adiar/internal/io/node_stream.h +++ b/src/adiar/internal/io/node_stream.h @@ -49,7 +49,7 @@ namespace adiar::internal /// \brief Create attached to a Decision Diagram. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const dd& diagram) - : parent_t(diagram._file, diagram._negate) + : parent_t(diagram.file_ptr(), diagram.is_negated()) {} //////////////////////////////////////////////////////////////////////////////////////////////// From 80658fc0cf652348ff433322bf83e1cde017f3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 09:09:24 +0200 Subject: [PATCH 03/30] Add 'shift_replace' for 'ptr_uint64' --- src/adiar/internal/data_types/ptr.h | 41 +++++++++- test/adiar/internal/data_types/test_ptr.cpp | 86 +++++++++++++++++++++ 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/adiar/internal/data_types/ptr.h b/src/adiar/internal/data_types/ptr.h index deedf59fa..28353836e 100644 --- a/src/adiar/internal/data_types/ptr.h +++ b/src/adiar/internal/data_types/ptr.h @@ -190,6 +190,11 @@ namespace adiar::internal // smallest type that can fit all the requested number of bits. using level_type = uint32_t; + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type able for a relative difference of levels. + //////////////////////////////////////////////////////////////////////////////////////////////// + using signed_level_type = int32_t; + protected: //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The maximal possible value for a level. @@ -332,6 +337,9 @@ namespace adiar::internal friend ptr_uint64 essential_replace(const ptr_uint64& p, const level_type new_level); + + friend ptr_uint64 + shift_replace(const ptr_uint64& p, const signed_level_type levels); //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// @@ -355,6 +363,11 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// using label_type = level_type; + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type able to hold the label of a variable. + //////////////////////////////////////////////////////////////////////////////////////////////// + using signed_label_type = signed_level_type; + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of a level identifier. //////////////////////////////////////////////////////////////////////////////////////////////// @@ -543,9 +556,8 @@ namespace adiar::internal static constexpr raw_type min_terminal = static_cast(terminal_level) << level_shift; // TODO (32-bit ADD): - // Add `max_terminal` at compile-time. Note, we are interested in the raw - // unsigned encoding (probably by bit-wise oring the minimum and the - // maximum). + // Add `max_terminal` at compile-time. Note, we are interested in the raw unsigned encoding + // (probably by bit-wise oring the minimum and the maximum). public: //////////////////////////////////////////////////////////////////////////////////////////////// @@ -836,6 +848,29 @@ namespace adiar::internal : (p._raw & ~ptr_uint64::flag_bit); } + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Shift the level by given amount. + ////////////////////////////////////////////////////////////////////////////////////////////////// + inline ptr_uint64 + shift_replace(const ptr_uint64& p, const ptr_uint64::signed_level_type levels) + { + // TODO (optimisation): Make this a branch-less computation! + if (levels == 0 || !p.is_node()) { return p; } + + // TODO (optimisation): Replace static_cast<...> with dynamic_cast<...> if always safe. + const bool subtract = levels < 0; + const ptr_uint64::level_type abs_levels = + static_cast(subtract ? -levels : levels); + + adiar_assert(subtract ? (abs_levels <= p.label()) + : (p.label() + abs_levels <= ptr_uint64::max_label)); + + const ptr_uint64::raw_type shifted_abs_levels = static_cast(abs_levels) + << ptr_uint64::level_shift; + + return subtract ? (p._raw - shifted_abs_levels) : (p._raw + shifted_abs_levels); + } + /* ======================================== CONVERSION ======================================== */ // TODO: Conversion constructor from node diff --git a/test/adiar/internal/data_types/test_ptr.cpp b/test/adiar/internal/data_types/test_ptr.cpp index d57222bf6..e626f62d9 100644 --- a/test/adiar/internal/data_types/test_ptr.cpp +++ b/test/adiar/internal/data_types/test_ptr.cpp @@ -859,6 +859,92 @@ go_bandit([]() { AssertThat(out, Is().EqualTo(ptr_uint64(42, 8))); }); }); + + describe("shift_replace(...)", [&]() { + it("leaves pointer as-is [x0 + 0]", [&]() { + const ptr_uint64 in(0, 0); + const ptr_uint64 out = shift_replace(in, +0); + AssertThat(out, Is().EqualTo(ptr_uint64(0, 0))); + }); + + it("leaves pointer as-is [x42 + 0]", [&]() { + const ptr_uint64 in(42, 0); + const ptr_uint64 out = shift_replace(in, +0); + AssertThat(out, Is().EqualTo(ptr_uint64(42, 0))); + }); + + it("leaves pointer as-is [false + 42]", [&]() { + const ptr_uint64 in(false); + const ptr_uint64 out = shift_replace(in, +42); + AssertThat(out, Is().EqualTo(ptr_uint64(false))); + }); + + it("leaves pointer as-is [true - 42]", [&]() { + const ptr_uint64 in(true); + const ptr_uint64 out = shift_replace(in, -42); + AssertThat(out, Is().EqualTo(ptr_uint64(true))); + }); + + it("leaves pointer as-is [nil - 3]", [&]() { + const ptr_uint64 in = ptr_uint64::nil(); + const ptr_uint64 out = shift_replace(in, -3); + AssertThat(out, Is().EqualTo(ptr_uint64::nil())); + }); + + it("shifts [x0 + 1]", [&]() { + const ptr_uint64 in(0, 0); + const ptr_uint64 out = shift_replace(in, +1); + AssertThat(out, Is().EqualTo(ptr_uint64(1, 0))); + }); + + it("shifts [x1 - 1]", [&]() { + const ptr_uint64 in(1, 0); + const ptr_uint64 out = shift_replace(in, -1); + AssertThat(out, Is().EqualTo(ptr_uint64(0, 0))); + }); + + it("shifts [x2 + 2]", [&]() { + const ptr_uint64 in(2, 0); + const ptr_uint64 out = shift_replace(in, 4); + AssertThat(out, Is().EqualTo(ptr_uint64(6, 0))); + }); + + it("shifts [x0 + max]", [&]() { + const ptr_uint64 in(0, 0); + const ptr_uint64 out = shift_replace(in, ptr_uint64::max_label); + AssertThat(out, Is().EqualTo(ptr_uint64(ptr_uint64::max_label, 0))); + }); + + it("shifts [xmax - max]", [&]() { + const ptr_uint64 in(ptr_uint64::max_label, 0); + const ptr_uint64 out = shift_replace(in, -static_cast(ptr_uint64::max_label)); + AssertThat(out, Is().EqualTo(ptr_uint64(0, 0))); + }); + + it("preserves 'id' when replacing variable [x2 + 2]", [&]() { + const ptr_uint64 in(2, 21); + const ptr_uint64 out = shift_replace(in, 2); + AssertThat(out, Is().EqualTo(ptr_uint64(4, 21))); + }); + + it("preserves 'id' when replacing variable [xmax - max]", [&]() { + const ptr_uint64 in(ptr_uint64::max_label, ptr_uint64::max_id); + const ptr_uint64 out = shift_replace(in, -static_cast(ptr_uint64::max_label)); + AssertThat(out, Is().EqualTo(ptr_uint64(0, ptr_uint64::max_id))); + }); + + it("preserves 'out_idx' when replacing variable", [&]() { + const ptr_uint64 in(42, 0, true); + const ptr_uint64 out = shift_replace(in, -21); + AssertThat(out, Is().EqualTo(ptr_uint64(21, 0, true))); + }); + + it("preserves 'flag' when replacing variable", [&]() { + const ptr_uint64 in = flag(ptr_uint64(21, 0)); + const ptr_uint64 out = shift_replace(in, +21); + AssertThat(out, Is().EqualTo(flag(ptr_uint64(42, 0)))); + }); + }); }); describe("ordering ( < )", [&]() { From 710ca6ab6117f2869804a01a6b5b8789f89171e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 09:15:51 +0200 Subject: [PATCH 04/30] Add 'shift_replace' for 'node' --- src/adiar/internal/data_types/node.h | 16 +++++++ test/adiar/internal/data_types/test_node.cpp | 50 ++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/adiar/internal/data_types/node.h b/src/adiar/internal/data_types/node.h index 352be7432..7cc415147 100644 --- a/src/adiar/internal/data_types/node.h +++ b/src/adiar/internal/data_types/node.h @@ -61,6 +61,11 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// static constexpr label_type max_label = pointer_type::max_label; + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type for a difference of levels. + //////////////////////////////////////////////////////////////////////////////////////////////// + using signed_label_type = pointer_type::signed_label_type; + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of this node's level identifier. //////////////////////////////////////////////////////////////////////////////////////////////// @@ -482,6 +487,17 @@ namespace adiar::internal { return u >= n.uid(); } + + /* =========================================== LEVELS ========================================= */ + inline node + shift_replace(const node& n, const node::signed_label_type levels) + { + const node::uid_type n_uid = shift_replace(n.uid().as_ptr(), levels); + const node::pointer_type n_low = shift_replace(n.low(), levels); + const node::pointer_type n_high = shift_replace(n.high(), levels); + + return { n_uid, n_low, n_high }; + } } #endif // ADIAR_INTERNAL_DATA_TYPES_NODE_H diff --git a/test/adiar/internal/data_types/test_node.cpp b/test/adiar/internal/data_types/test_node.cpp index 0078ffb8b..a3d1e2185 100644 --- a/test/adiar/internal/data_types/test_node.cpp +++ b/test/adiar/internal/data_types/test_node.cpp @@ -2,10 +2,10 @@ go_bandit([]() { describe("adiar/internal/data_types/node.h", []() { - describe("node", [&]() { - const ptr_uint64 terminal_F = ptr_uint64(false); - const ptr_uint64 terminal_T = ptr_uint64(true); + const ptr_uint64 terminal_F = ptr_uint64(false); + const ptr_uint64 terminal_T = ptr_uint64(true); + describe("node", [&]() { it("should be a POD", [&]() { AssertThat(std::is_pod::value, Is().True()); }); it("should take up 24 bytes of memory", [&]() { @@ -372,5 +372,49 @@ go_bandit([]() { [&]() { AssertThat(!node(true), Is().EqualTo(node(false))); }); }); }); + + describe("shift_replace(const node&, ...)", [&]() { + it("leaves node as-is [levels = 0]", [&]() { + const node in = node(0, 42, terminal_F, terminal_T); + const node out = shift_replace(in, +0); + AssertThat(in, Is().EqualTo(out)); + }); + + it("leaves node as-is [levels = 0]", [&]() { + const node in = node(21, 0, node::pointer_type(42, 2), terminal_T); + const node out = shift_replace(in, -0); + AssertThat(in, Is().EqualTo(out)); + }); + + it("leaves node as-is [F]", [&]() { + const node in = node(false); + const node out = shift_replace(in, -3); + AssertThat(in, Is().EqualTo(out)); + }); + + it("leaves node as-is [T]", [&]() { + const node in = node(true); + const node out = shift_replace(in, -18); + AssertThat(in, Is().EqualTo(out)); + }); + + it("shifts uid level", [&]() { + const node in = node(21, 0, terminal_F, terminal_T); + const node out = shift_replace(in, -16); + + AssertThat(out.uid(), Is().EqualTo(node::uid_type(21 - 16, 0))); + AssertThat(out.low(), Is().EqualTo(terminal_F)); + AssertThat(out.high(), Is().EqualTo(terminal_T)); + }); + + it("shifts children's level too", [&]() { + const node in = node(4, 4, node::pointer_type(8, 12), node::pointer_type(7, 2)); + const node out = shift_replace(in, +2); + + AssertThat(out.uid(), Is().EqualTo(node::uid_type(4 + 2, 4))); + AssertThat(out.low(), Is().EqualTo(node::uid_type(8 + 2, 12))); + AssertThat(out.high(), Is().EqualTo(node::uid_type(7 + 2, 2))); + }); + }); }); }); From fda5b9376e5032ffd49a5ded2787fef4ec6ac079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:01:33 +0200 Subject: [PATCH 05/30] Debug 'level_info' and add 'shift_replace(...)' --- makefile | 3 + src/adiar/internal/data_types/level_info.h | 161 +++++++++++------- test/adiar/internal/data_types/CMakeLists.txt | 15 +- .../internal/data_types/test_level_info.cpp | 156 +++++++++++++++++ test/test.cpp | 1 + 5 files changed, 267 insertions(+), 69 deletions(-) create mode 100644 test/adiar/internal/data_types/test_level_info.cpp diff --git a/makefile b/makefile index 833a322ba..d3284f510 100644 --- a/makefile +++ b/makefile @@ -156,6 +156,9 @@ test/adiar/internal/data_types/arc: test/adiar/internal/data_types/convert: $(MAKE) $(MAKE_FLAGS) test TEST_FOLDER=test/adiar/internal/data_types TEST_NAME=convert +test/adiar/internal/data_types/level_info: + $(MAKE) $(MAKE_FLAGS) test TEST_FOLDER=test/adiar/internal/data_types TEST_NAME=level_info + test/adiar/internal/data_types/node: $(MAKE) $(MAKE_FLAGS) test TEST_FOLDER=test/adiar/internal/data_types TEST_NAME=node diff --git a/src/adiar/internal/data_types/level_info.h b/src/adiar/internal/data_types/level_info.h index 5d854b7d6..398c2387e 100644 --- a/src/adiar/internal/data_types/level_info.h +++ b/src/adiar/internal/data_types/level_info.h @@ -1,149 +1,186 @@ #ifndef ADIAR_INTERNAL_DATA_TYPES_LEVEL_INFO_H #define ADIAR_INTERNAL_DATA_TYPES_LEVEL_INFO_H +#include #include namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Meta information on a single level in a decision diagram. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// class level_info { // TODO (Larger variable identifiers): // template public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of a variable level. - //////////////////////////////////////////////////////////////////////////// - using level_type = ptr_uint64::label_type; + //////////////////////////////////////////////////////////////////////////////////////////////// + using level_type = ptr_uint64::level_type; - /* ================================ VARIABLES =========================== */ + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type of a difference between variable levels. + //////////////////////////////////////////////////////////////////////////////////////////////// + using signed_level_type = ptr_uint64::signed_level_type; + + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type of a variable label. + //////////////////////////////////////////////////////////////////////////////////////////////// + using label_type = ptr_uint64::level_type; + + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Type of a difference between variable labels. + //////////////////////////////////////////////////////////////////////////////////////////////// + using signed_label_type = ptr_uint64::signed_level_type; + + /* ========================================== VARIABLES ===================================== */ private: - level_type _label; + level_type _level; size_t _width; - /* ============================== CONSTRUCTORS ========================== */ + /* ======================================== CONSTRUCTORS ==================================== */ public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Default construction (trivial). /// - /// \details The default, copy, and move construction has to be `default` to - /// ensure it is a *POD* and hence can be used by TPIE's files. - //////////////////////////////////////////////////////////////////////////// + /// \details The default, copy, and move construction has to be `default` to ensure it is a + /// *POD* and hence can be used by TPIE's files. + //////////////////////////////////////////////////////////////////////////////////////////////// level_info() = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Copy construction (trivial). /// - /// \details The default, copy, and move construction has to be `default` to - /// ensure it is a *POD* and hence can be used by TPIE's files. - //////////////////////////////////////////////////////////////////////////// + /// \details The default, copy, and move construction has to be `default` to ensure it is a + /// *POD* and hence can be used by TPIE's files. + //////////////////////////////////////////////////////////////////////////////////////////////// level_info(const level_info& li) = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Move construction (trivial). /// - /// \details The default, copy, and move construction has to be `default` to - /// ensure it is a *POD* and hence can be used by TPIE's files. - //////////////////////////////////////////////////////////////////////////// + /// \details The default, copy, and move construction has to be `default` to ensure it is a + /// *POD* and hence can be used by TPIE's files. + //////////////////////////////////////////////////////////////////////////////////////////////// level_info(level_info&& li) = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Destruction (trivial). /// - /// \details The destructor has to be `default` to ensure it is a *POD* and - /// hence can be used by TPIE's files. - //////////////////////////////////////////////////////////////////////////// + /// \details The destructor has to be `default` to ensure it is a *POD* and hence can be used by + /// TPIE's files. + //////////////////////////////////////////////////////////////////////////////////////////////// ~level_info() = default; - //////////////////////////////////////////////////////////////////////////// - /// \brief Create a level_info for a variable and a certain width when using - /// the identity variable ordering. - //////////////////////////////////////////////////////////////////////////// - level_info(level_type label, size_t width) - : _label(label) + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Create a level_info for a variable and a certain width when using the identity + /// variable ordering. + //////////////////////////////////////////////////////////////////////////////////////////////// + level_info(level_type level, size_t width) + : _level(level) , _width(width) - {} + { + adiar_assert(level <= ptr_uint64::max_label, "Level should be valid in 'ptr_uint64'"); + adiar_assert(width != 0, "Empty levels are never to-be recorded"); + adiar_assert(width <= ptr_uint64::max_id + 1, "A level should be valid in 'ptr_uint64'"); + } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Copy assignment (trivial). /// - /// \details The copy and move assignment has to be `default` to ensure it - /// is a *POD* and hence can be used by TPIE's files. - //////////////////////////////////////////////////////////////////////////// + /// \details The copy and move assignment has to be `default` to ensure it is a *POD* and hence + /// can be used by TPIE's files. + //////////////////////////////////////////////////////////////////////////////////////////////// level_info& operator=(const level_info& li) = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Move assignment (trivial). /// - /// \details The copy and move assignment has to be `default` to ensure it - /// is a *POD* and hence can be used by TPIE's files. - //////////////////////////////////////////////////////////////////////////// + /// \details The copy and move assignment has to be `default` to ensure it is a *POD* and hence + /// can be used by TPIE's files. + //////////////////////////////////////////////////////////////////////////////////////////////// level_info& operator=(level_info&& li) = default; - /* ============================ MEMBER FUNCTIONS ======================== */ + /* ====================================== MEMBER FUNCTIONS ================================== */ public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the label for a level. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the level. + //////////////////////////////////////////////////////////////////////////////////////////////// level_type - label() const + level() const { - return _label; + return this->_level; } - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the level. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the label for a level. + //////////////////////////////////////////////////////////////////////////////////////////////// level_type - level() const + label() const { - return _label; + return this->level(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the width (i.e. number of nodes) of this level. - //////////////////////////////////////////////////////////////////////////// - level_type + //////////////////////////////////////////////////////////////////////////////////////////////// + size_t width() const { - return _width; + return this->_width; } - /* =============================== OPERATORS ============================ */ + /* ========================================= OPERATORS ====================================== */ public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether all entries on this level match. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// inline bool operator==(const level_info& o) const { - return this->_label == o._label && this->_width == o._width; + return this->_level == o._level && this->_width == o._width; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether any entry on this level mismatches. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// inline bool operator!=(const level_info& o) const { return !(*this == o); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the level info for the negated decision diagram. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// level_info operator!() const { return *this; } }; + + /* ============================================ LEVELS ======================================== */ + inline level_info + shift_replace(const level_info& li, const level_info::signed_level_type levels) + { + using level_type = level_info::level_type; + using signed_level_type = level_info::signed_level_type; + + adiar_assert(levels < 0 ? (std::abs(levels) <= li.level()) + : (li.level() + levels <= ptr_uint64::max_label)); + + // TODO: Use dynamic casts instead? + const level_type new_level = + static_cast(static_cast(li.level()) + levels); + + return { new_level, li.width() }; + } } #endif // ADIAR_INTERNAL_DATA_TYPES_LEVEL_INFO_H diff --git a/test/adiar/internal/data_types/CMakeLists.txt b/test/adiar/internal/data_types/CMakeLists.txt index 6feab3b73..cbd81d00c 100644 --- a/test/adiar/internal/data_types/CMakeLists.txt +++ b/test/adiar/internal/data_types/CMakeLists.txt @@ -1,7 +1,8 @@ -add_test(adiar-internal-data_types-arc test_arc.cpp) -add_test(adiar-internal-data_types-convert test_convert.cpp) -add_test(adiar-internal-data_types-node test_node.cpp) -add_test(adiar-internal-data_types-ptr test_ptr.cpp) -add_test(adiar-internal-data_types-request test_request.cpp) -add_test(adiar-internal-data_types-tuple test_tuple.cpp) -add_test(adiar-internal-data_types-uid test_uid.cpp) +add_test(adiar-internal-data_types-arc test_arc.cpp) +add_test(adiar-internal-data_types-convert test_convert.cpp) +add_test(adiar-internal-data_types-level_info test_level_info.cpp) +add_test(adiar-internal-data_types-node test_node.cpp) +add_test(adiar-internal-data_types-ptr test_ptr.cpp) +add_test(adiar-internal-data_types-request test_request.cpp) +add_test(adiar-internal-data_types-tuple test_tuple.cpp) +add_test(adiar-internal-data_types-uid test_uid.cpp) diff --git a/test/adiar/internal/data_types/test_level_info.cpp b/test/adiar/internal/data_types/test_level_info.cpp new file mode 100644 index 000000000..16eb42d61 --- /dev/null +++ b/test/adiar/internal/data_types/test_level_info.cpp @@ -0,0 +1,156 @@ +#include "../../../test.h" + +#include + +go_bandit([]() { + describe("adiar/internal/data_types/level_info.h", []() { + it("should be a POD", []() { AssertThat(std::is_pod::value, Is().True()); }); + + it("should take up 16 bytes of memory", [&]() { + const level_info li(42, 1024); + AssertThat(sizeof(li), Is().EqualTo(2u * 8u)); + }); + + describe(".level(), .label()", [&] { + it("creates and retrieves from (0,1)", [&]() { + const level_info li(0, 1); + AssertThat(li.level(), Is().EqualTo(0u)); + AssertThat(li.label(), Is().EqualTo(0u)); + }); + + it("creates and retrieves from (0,2)", [&]() { + const level_info li(0, 2); + AssertThat(li.level(), Is().EqualTo(0u)); + AssertThat(li.label(), Is().EqualTo(0u)); + }); + + it("creates and retrieves from (42,8)", [&]() { + const level_info li(42, 8); + AssertThat(li.level(), Is().EqualTo(42u)); + AssertThat(li.label(), Is().EqualTo(42u)); + }); + + it("creates and retrieves from (max,1)", [&]() { + const level_info li(ptr_uint64::max_label, 1); + AssertThat(li.level(), Is().EqualTo(ptr_uint64::max_label)); + AssertThat(li.level(), Is().EqualTo(ptr_uint64::max_label)); + }); + + it("creates and retrieves from (max,2)", [&]() { + const level_info li(ptr_uint64::max_label, 2); + AssertThat(li.level(), Is().EqualTo(ptr_uint64::max_label)); + AssertThat(li.level(), Is().EqualTo(ptr_uint64::max_label)); + }); + }); + + describe(".width()", [&] { + it("creates and retrieves from (0,1)", [&]() { + const level_info li(0, 1); + AssertThat(li.width(), Is().EqualTo(1u)); + }); + + it("creates and retrieves from (0,2)", [&]() { + const level_info li(0, 2); + AssertThat(li.width(), Is().EqualTo(2u)); + }); + + it("creates and retrieves from (42,max)", [&]() { + const level_info li(42, ptr_uint64::max_id); + AssertThat(li.width(), Is().EqualTo(ptr_uint64::max_id)); + }); + + it("creates and retrieves from (42,max)", [&]() { + const level_info li(42, ptr_uint64::max_id + 1); + AssertThat(li.width(), Is().EqualTo(ptr_uint64::max_id + 1)); + }); + }); + + describe("operator ==", [&] { + it("checks (0,1) == (0,1)", [&]() { + const level_info li_1(0, 1); + const level_info li_2(0, 1); + AssertThat(li_1, Is().EqualTo(li_2)); + }); + + it("checks (2,1) == (2,1)", [&]() { + const level_info li_1(2, 1); + const level_info li_2(2, 1); + AssertThat(li_1, Is().EqualTo(li_2)); + }); + + it("checks (1,2) == (1,2)", [&]() { + const level_info li_1(1, 2); + const level_info li_2(1, 2); + AssertThat(li_1, Is().EqualTo(li_2)); + }); + + it("checks (42,21) == (42,21)", [&]() { + const level_info li_1(42, 21); + const level_info li_2(42, 21); + AssertThat(li_1, Is().EqualTo(li_2)); + }); + + it("checks (max,max+1) == (max,max+1)", [&]() { + const level_info li_1(ptr_uint64::max_label, ptr_uint64::max_id + 1); + const level_info li_2(ptr_uint64::max_label, ptr_uint64::max_id + 1); + AssertThat(li_1, Is().EqualTo(li_2)); + }); + + it("checks (2,1) != (2,2)", [&]() { + const level_info li_1(2, 1); + const level_info li_2(2, 2); + AssertThat(li_1, Is().Not().EqualTo(li_2)); + }); + + it("checks (1,2) != (2,2)", [&]() { + const level_info li_1(1, 2); + const level_info li_2(2, 2); + AssertThat(li_1, Is().Not().EqualTo(li_2)); + }); + + it("checks (1,2) != (2,1)", [&]() { + const level_info li_1(1, 2); + const level_info li_2(2, 1); + AssertThat(li_1, Is().Not().EqualTo(li_2)); + }); + }); + + describe("shift_replace(const level_info&, ...)", [&] { + it("shifts (0,1) [+1]", [&]() { + AssertThat(shift_replace(level_info(0, 1), +1), Is().EqualTo(level_info(1, 1))); + }); + + it("shifts (0,1) [+2]", [&]() { + AssertThat(shift_replace(level_info(0, 1), +2), Is().EqualTo(level_info(2, 1))); + }); + + it("shifts (2,1) [+1]", [&]() { + AssertThat(shift_replace(level_info(2, 1), +1), Is().EqualTo(level_info(3, 1))); + }); + + it("shifts (2,2) [+1]", [&]() { + AssertThat(shift_replace(level_info(2, 2), +1), Is().EqualTo(level_info(3, 2))); + }); + + it("shifts (2,1) [-1]", [&]() { + AssertThat(shift_replace(level_info(2, 1), -1), Is().EqualTo(level_info(1, 1))); + }); + + it("shifts (2,2) [-1]", [&]() { + AssertThat(shift_replace(level_info(2, 2), -1), Is().EqualTo(level_info(1, 2))); + }); + + it("shifts (0,1) [+max]", [&]() { + AssertThat(shift_replace(level_info(0, 1), +ptr_uint64::max_label), + Is().EqualTo(level_info(ptr_uint64::max_label, 1))); + }); + + it("shifts (max,1) [-max]", [&]() { + AssertThat( + shift_replace(level_info(ptr_uint64::max_label, 1), + -static_cast(ptr_uint64::max_label)), + Is().EqualTo(level_info(0, 1))); + }); + }); + }); +}); diff --git a/test/test.cpp b/test/test.cpp index d473e07e1..5e17623a2 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -50,6 +50,7 @@ go_bandit([]() { #include "adiar/internal/data_structures/test_levelized_priority_queue.cpp" #include "adiar/internal/data_types/test_arc.cpp" #include "adiar/internal/data_types/test_convert.cpp" +#include "adiar/internal/data_types/test_level_info.cpp" #include "adiar/internal/data_types/test_node.cpp" #include "adiar/internal/data_types/test_ptr.cpp" #include "adiar/internal/data_types/test_request.cpp" From cb5f599e18c1b213b9100574ba6204fb65bddecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:04:53 +0200 Subject: [PATCH 06/30] Fix incorrect name of type in 'level_info_stream' according to style guide --- src/adiar/internal/io/levelized_file_stream.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/adiar/internal/io/levelized_file_stream.h b/src/adiar/internal/io/levelized_file_stream.h index 4faba6464..17e854b05 100644 --- a/src/adiar/internal/io/levelized_file_stream.h +++ b/src/adiar/internal/io/levelized_file_stream.h @@ -186,7 +186,7 @@ namespace adiar::internal template class level_info_stream : public file_stream { - using parent_t = file_stream; + using parent_type = file_stream; public: //////////////////////////////////////////////////////////////////////////////////////////////// @@ -203,7 +203,7 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const file& f) { - parent_t::attach(f); + parent_type::attach(f); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -211,7 +211,7 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// level_info_stream(const adiar::shared_ptr>& f) { - parent_t::attach(f); + parent_type::attach(f); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -262,7 +262,7 @@ namespace adiar::internal attach(const levelized_file& lf) { if (!lf.exists()) lf.__touch(); - parent_t::attach(lf._level_info_file, nullptr, false); + parent_type::attach(lf._level_info_file, nullptr, false); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -273,7 +273,7 @@ namespace adiar::internal attach(const adiar::shared_ptr>& lf) { if (!lf->exists()) lf->touch(); - parent_t::attach(lf->_level_info_file, lf, false); + parent_type::attach(lf->_level_info_file, lf, false); } //////////////////////////////////////////////////////////////////////////////////////////////// From 33ee67cce29332d5f112d5913214d547e69a528d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:05:24 +0200 Subject: [PATCH 07/30] Update 'level_info_stream' to code style --- src/adiar/internal/io/levelized_file_stream.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/adiar/internal/io/levelized_file_stream.h b/src/adiar/internal/io/levelized_file_stream.h index 17e854b05..327722af3 100644 --- a/src/adiar/internal/io/levelized_file_stream.h +++ b/src/adiar/internal/io/levelized_file_stream.h @@ -183,10 +183,10 @@ namespace adiar::internal ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Stream to access per-level meta information. ////////////////////////////////////////////////////////////////////////////////////////////////// - template - class level_info_stream : public file_stream + template + class level_info_stream : public file_stream { - using parent_type = file_stream; + using parent_type = file_stream; public: //////////////////////////////////////////////////////////////////////////////////////////////// @@ -195,8 +195,8 @@ namespace adiar::internal level_info_stream() = default; //////////////////////////////////////////////////////////////////////////////////////////////// - level_info_stream(const level_info_stream&) = delete; - level_info_stream(level_info_stream&&) = delete; + level_info_stream(const level_info_stream&) = delete; + level_info_stream(level_info_stream&&) = delete; //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a file. From 448037d505379f25fcb81fef3260043114f2b70c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:20:05 +0200 Subject: [PATCH 08/30] Add missing unit tests for 'level_info_stream' --- .../adiar/internal/io/test_levelized_file.cpp | 71 +++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/test/adiar/internal/io/test_levelized_file.cpp b/test/adiar/internal/io/test_levelized_file.cpp index 037526f87..26cc11905 100644 --- a/test/adiar/internal/io/test_levelized_file.cpp +++ b/test/adiar/internal/io/test_levelized_file.cpp @@ -959,25 +959,70 @@ go_bandit([]() { }); describe("levelized_file() + levelized_file_writer + level_info_stream", []() { - it("reads by default level information in reverse", []() { - levelized_file lf; - levelized_file_writer lfw(lf); + levelized_file lf; + levelized_file_writer lfw(lf); - lfw.push<0>(-1); - lfw.push<0>(1); - lfw.push<1>(-1); - lfw.push<0>(2); - lfw.push<1>(1); - lfw.push(level_info{ 0u, 2u }); - lfw.push(level_info{ 1u, 3u }); + lfw.push<0>(-1); + lfw.push<0>(1); + lfw.push<1>(-1); + lfw.push<0>(2); + lfw.push<1>(1); + lfw.push(level_info{ 1u, 2u }); + lfw.push(level_info{ 3u, 3u }); - lfw.detach(); + lfw.detach(); + + it("pulls by default level information in reverse", [&]() { + level_info_stream fs(lf); + AssertThat(fs.can_pull(), Is().True()); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 3u, 3u })); + + AssertThat(fs.can_pull(), Is().True()); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 1u, 2u })); + + AssertThat(fs.can_pull(), Is().False()); + }); + + it("peeks by default level information in reverse", [&]() { level_info_stream fs(lf); + AssertThat(fs.can_pull(), Is().True()); - AssertThat(fs.pull(), Is().EqualTo(level_info{ 1u, 3u })); + AssertThat(fs.peek(), Is().EqualTo(level_info{ 3u, 3u })); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 3u, 3u })); + AssertThat(fs.can_pull(), Is().True()); - AssertThat(fs.pull(), Is().EqualTo(level_info{ 0u, 2u })); + AssertThat(fs.peek(), Is().EqualTo(level_info{ 1u, 2u })); + AssertThat(fs.peek(), Is().EqualTo(level_info{ 1u, 2u })); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 1u, 2u })); + + AssertThat(fs.can_pull(), Is().False()); + }); + + it("can read level information forwards", [&]() { + level_info_stream fs(lf); + + AssertThat(fs.can_pull(), Is().True()); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 1u, 2u })); + + AssertThat(fs.can_pull(), Is().True()); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 3u, 3u })); + + AssertThat(fs.can_pull(), Is().False()); + }); + + it("can peek level information forwards", [&]() { + level_info_stream fs(lf); + + AssertThat(fs.can_pull(), Is().True()); + AssertThat(fs.peek(), Is().EqualTo(level_info{ 1u, 2u })); + AssertThat(fs.peek(), Is().EqualTo(level_info{ 1u, 2u })); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 1u, 2u })); + + AssertThat(fs.can_pull(), Is().True()); + AssertThat(fs.peek(), Is().EqualTo(level_info{ 3u, 3u })); + AssertThat(fs.pull(), Is().EqualTo(level_info{ 3u, 3u })); + AssertThat(fs.can_pull(), Is().False()); }); }); From c06456a2a9d79a066d7185876ab0fbfaadd3a24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:23:43 +0200 Subject: [PATCH 09/30] Fix incorrect type name according to style guide --- src/adiar/internal/io/node_stream.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/adiar/internal/io/node_stream.h b/src/adiar/internal/io/node_stream.h index 6241517ba..bd7cdc48f 100644 --- a/src/adiar/internal/io/node_stream.h +++ b/src/adiar/internal/io/node_stream.h @@ -19,7 +19,7 @@ namespace adiar::internal template class node_stream : public levelized_file_stream { - using parent_t = levelized_file_stream; + using parent_type = levelized_file_stream; public: //////////////////////////////////////////////////////////////////////////////////////////////// @@ -35,21 +35,21 @@ namespace adiar::internal /// \brief Create attached to a node file. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const levelized_file& file, const bool negate = false) - : parent_t(file, negate) + : parent_type(file, negate) {} //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared node file. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const shared_ptr>& file, const bool negate = false) - : parent_t(file, negate) + : parent_type(file, negate) {} //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a Decision Diagram. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const dd& diagram) - : parent_t(diagram.file_ptr(), diagram.is_negated()) + : parent_type(diagram.file_ptr(), diagram.is_negated()) {} //////////////////////////////////////////////////////////////////////////////////////////////// @@ -58,7 +58,7 @@ namespace adiar::internal bool can_pull() const { - return parent_t::template can_pull<0>(); + return parent_type::template can_pull<0>(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -69,7 +69,7 @@ namespace adiar::internal const node pull() { - return parent_t::template pull<0>(); + return parent_type::template pull<0>(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -80,7 +80,7 @@ namespace adiar::internal const node peek() { - return parent_t::template peek<0>(); + return parent_type::template peek<0>(); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -93,7 +93,7 @@ namespace adiar::internal const node seek(const node::uid_type& u) { - return parent_t::_streams[0].seek(u); + return parent_type::_streams[0].seek(u); } }; } From f7ad53aa0920bb324d94d6fc9bac83611537e64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:28:53 +0200 Subject: [PATCH 10/30] Add missing tests and remove duplicated inputs for tests for 'node_stream' --- src/adiar/internal/io/node_stream.h | 4 +- test/adiar/internal/io/test_node_file.cpp | 794 ++++++++++++---------- 2 files changed, 448 insertions(+), 350 deletions(-) diff --git a/src/adiar/internal/io/node_stream.h b/src/adiar/internal/io/node_stream.h index bd7cdc48f..9c46ca8be 100644 --- a/src/adiar/internal/io/node_stream.h +++ b/src/adiar/internal/io/node_stream.h @@ -34,14 +34,14 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a node file. //////////////////////////////////////////////////////////////////////////////////////////////// - node_stream(const levelized_file& file, const bool negate = false) + node_stream(const levelized_file& file, bool negate = false) : parent_type(file, negate) {} //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared node file. //////////////////////////////////////////////////////////////////////////////////////////////// - node_stream(const shared_ptr>& file, const bool negate = false) + node_stream(const shared_ptr>& file, bool negate = false) : parent_type(file, negate) {} diff --git a/test/adiar/internal/io/test_node_file.cpp b/test/adiar/internal/io/test_node_file.cpp index 4a3e8addd..b0e25be91 100644 --- a/test/adiar/internal/io/test_node_file.cpp +++ b/test/adiar/internal/io/test_node_file.cpp @@ -877,8 +877,121 @@ go_bandit([]() { }); describe("node_writer + node_stream", []() { - // TODO: stream: reads backwards by default - // TODO: stream: reads forwards if desired + describe(".can_pull(), .pull(), .peek()", []() { + const node n3(2, 1, node::pointer_type(false), node::pointer_type(true)); + const node n2(2, 0, node::pointer_type(true), node::pointer_type(false)); + const node n1(0, 0, node::uid_type(2, 0), node::uid_type(2, 1)); + + levelized_file nf; + { + node_writer nw(nf); + nw << n3 << n2 << n1; + } + + it("pulls top-down (backwards) by default", [&]() { + node_stream<> ns(nf); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n1)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n2)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n3)); + + AssertThat(ns.can_pull(), Is().False()); + }); + + it("pulls and peeks top-down (backwards) by default", [&]() { + node_stream<> ns(nf); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), Is().EqualTo(n1)); + AssertThat(ns.pull(), Is().EqualTo(n1)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), Is().EqualTo(n2)); + AssertThat(ns.peek(), Is().EqualTo(n2)); + AssertThat(ns.pull(), Is().EqualTo(n2)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), Is().EqualTo(n3)); + AssertThat(ns.pull(), Is().EqualTo(n3)); + + AssertThat(ns.can_pull(), Is().False()); + }); + + it("pulls bottom-up (forwards) if requested", [&]() { + node_stream ns(nf); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n3)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n2)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n1)); + + AssertThat(ns.can_pull(), Is().False()); + }); + + it("pulls and peeks bottom-up (forwards) if requested", [&]() { + node_stream ns(nf); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), Is().EqualTo(n3)); + AssertThat(ns.peek(), Is().EqualTo(n3)); + AssertThat(ns.pull(), Is().EqualTo(n3)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n2)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), Is().EqualTo(n1)); + AssertThat(ns.pull(), Is().EqualTo(n1)); + + AssertThat(ns.can_pull(), Is().False()); + }); + + it("negates pulls on-the-fly", [&]() { + node_stream<> ns(nf, true); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), Is().EqualTo(n1)); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), + Is().EqualTo(node(2, 0, node::pointer_type(false), node::pointer_type(true)))); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.pull(), + Is().EqualTo(node(2, 1, node::pointer_type(true), node::pointer_type(false)))); + + AssertThat(ns.can_pull(), Is().False()); + }); + + it("negates peeks on-the-fly", [&]() { + node_stream<> ns(nf, true); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), Is().EqualTo(n1)); + ns.pull(); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), + Is().EqualTo(node(2, 0, node::pointer_type(false), node::pointer_type(true)))); + ns.pull(); + + AssertThat(ns.can_pull(), Is().True()); + AssertThat(ns.peek(), + Is().EqualTo(node(2, 1, node::pointer_type(true), node::pointer_type(false)))); + ns.pull(); + + AssertThat(ns.can_pull(), Is().False()); + }); + }); describe(".seek(const node::uid_type &u)", []() { it("can seek in False sink", [&]() { @@ -913,36 +1026,28 @@ go_bandit([]() { Is().EqualTo(node(true))); }); - it("can seek existing elements", [&]() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(1, 1, node::pointer_type(false), node::pointer_type(true)) - << node(1, 0, node::pointer_type(true), node::pointer_type(false)) - << node(0, 0, node::uid_type(1, 0), node::uid_type(1, 1)); - } + levelized_file nf; + { + node_writer nw(nf); + nw << node(2, 1, node::pointer_type(false), node::pointer_type(true)) + << node(2, 0, node::pointer_type(true), node::pointer_type(false)) + << node(0, 0, node::pointer_type(2, 0), node::pointer_type(2, 1)); + } + it("can seek existing elements", [&]() { node_stream<> ns(nf); AssertThat(ns.seek(node::uid_type(0, 0)), - Is().EqualTo(node(0, 0, node::uid_type(1, 0), node::uid_type(1, 1)))); - AssertThat(ns.seek(node::uid_type(1, 1)), - Is().EqualTo(node(1, 1, node::pointer_type(false), node::pointer_type(true)))); + Is().EqualTo(node(0, 0, node::uid_type(2, 0), node::uid_type(2, 1)))); + AssertThat(ns.seek(node::uid_type(2, 1)), + Is().EqualTo(node(2, 1, node::pointer_type(false), node::pointer_type(true)))); }); it("can seek non-existing element in the middle ", [&]() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(2, 1, node::pointer_type(false), node::pointer_type(true)) - << node(2, 0, node::pointer_type(true), node::pointer_type(false)) - << node(0, 0, node::pointer_type(1, 0), node::pointer_type(1, 1)); - } - node_stream<> ns(nf); AssertThat(ns.seek(node::uid_type(0, 0)), - Is().EqualTo(node(0, 0, node::pointer_type(1, 0), node::pointer_type(1, 1)))); + Is().EqualTo(node(0, 0, node::pointer_type(2, 0), node::pointer_type(2, 1)))); AssertThat(ns.seek(node::uid_type(1, 1)), Is().EqualTo(node(2, 0, node::pointer_type(true), node::pointer_type(false)))); AssertThat(ns.seek(node::uid_type(1, 2)), @@ -954,456 +1059,449 @@ go_bandit([]() { }); it("can seek past end [1]", [&]() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(1, 1, node::pointer_type(false), node::pointer_type(true)) - << node(1, 0, node::pointer_type(true), node::pointer_type(false)) - << node(0, 0, node::pointer_type(1, 0), node::pointer_type(1, 1)); - } - node_stream<> ns(nf); AssertThat(ns.seek(node::uid_type(node::max_label, node::max_id)), - Is().EqualTo(node(1, 1, node::pointer_type(false), node::pointer_type(true)))); + Is().EqualTo(node(2, 1, node::pointer_type(false), node::pointer_type(true)))); }); it("can seek past end [2]", [&]() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(1, 1, node::pointer_type(false), node::pointer_type(true)) - << node(1, 0, node::pointer_type(true), node::pointer_type(false)) - << node(0, 0, node::pointer_type(1, 0), node::pointer_type(1, 1)); - } - node_stream<> ns(nf); AssertThat(ns.seek(node::uid_type(0, 0)), - Is().EqualTo(node(0, 0, node::pointer_type(1, 0), node::pointer_type(1, 1)))); - AssertThat(ns.seek(node::uid_type(1, 1)), - Is().EqualTo(node(1, 1, node::pointer_type(false), node::pointer_type(true)))); + Is().EqualTo(node(0, 0, node::pointer_type(2, 0), node::pointer_type(2, 1)))); + AssertThat(ns.seek(node::uid_type(2, 1)), + Is().EqualTo(node(2, 1, node::pointer_type(false), node::pointer_type(true)))); AssertThat(ns.seek(node::uid_type(2, 0)), - Is().EqualTo(node(1, 1, node::pointer_type(false), node::pointer_type(true)))); + Is().EqualTo(node(2, 1, node::pointer_type(false), node::pointer_type(true)))); + }); + + it("negates seek result", [&]() { + node_stream<> ns(nf, true); + + AssertThat(ns.seek(node::uid_type(0, 0)), + Is().EqualTo(node(0, 0, node::pointer_type(2, 0), node::pointer_type(2, 1)))); + AssertThat(ns.seek(node::uid_type(1, 0)), + Is().EqualTo(node(2, 0, node::pointer_type(false), node::pointer_type(true)))); + AssertThat(ns.seek(node::uid_type(2, 1)), + Is().EqualTo(node(2, 1, node::pointer_type(true), node::pointer_type(false)))); }); // TODO: reversed }); + }); - describe("node_writer + node_random_access", []() { - /* - // 1 ---- A - // / \ - // F T - */ - const node A_n1 = - node(1, node::max_id, node::pointer_type(false), node::pointer_type(true)); + describe("node_writer + node_random_access", []() { + /* + // 1 ---- A + // / \ + // F T + */ + const node A_n1 = node(1, node::max_id, node::pointer_type(false), node::pointer_type(true)); - levelized_file nf_A; - { - node_writer nw(nf_A); - nw << A_n1; - } + levelized_file nf_A; + { + node_writer nw(nf_A); + nw << A_n1; + } - /* - // _1_ ---- x0 - // / \ - // _2_ \ ---- x1 - // / \ \ - // 3 4 5 ---- x2 - // / \ / \ / \ - // F 6 7 T ---- x4 - // / \ / \ - // T F F T - */ - const node B_n7 = - node(4, node::max_id, node::pointer_type(false), node::pointer_type(true)); - const node B_n6 = - node(4, node::max_id - 1, node::pointer_type(true), node::pointer_type(false)); - const node B_n5 = node(2, node::max_id, B_n7.uid(), node::pointer_type(true)); - const node B_n4 = node(2, node::max_id - 1, B_n6.uid(), B_n7.uid()); - const node B_n3 = node(2, node::max_id - 2, node::pointer_type(false), B_n6.uid()); - const node B_n2 = node(1, node::max_id, B_n3.uid(), B_n4.uid()); - const node B_n1 = node(0, node::max_id, B_n2.uid(), B_n5.uid()); - - levelized_file nf_B; - { - node_writer nw(nf_B); - nw << B_n7 << B_n6 << B_n5 << B_n4 << B_n3 << B_n2 << B_n1; - } + /* + // _1_ ---- x0 + // / \ + // _2_ \ ---- x1 + // / \ \ + // 3 4 5 ---- x2 + // / \ / \ / \ + // F 6 7 T ---- x4 + // / \ / \ + // T F F T + */ + const node B_n7 = node(4, node::max_id, node::pointer_type(false), node::pointer_type(true)); + const node B_n6 = + node(4, node::max_id - 1, node::pointer_type(true), node::pointer_type(false)); + const node B_n5 = node(2, node::max_id, B_n7.uid(), node::pointer_type(true)); + const node B_n4 = node(2, node::max_id - 1, B_n6.uid(), B_n7.uid()); + const node B_n3 = node(2, node::max_id - 2, node::pointer_type(false), B_n6.uid()); + const node B_n2 = node(1, node::max_id, B_n3.uid(), B_n4.uid()); + const node B_n1 = node(0, node::max_id, B_n2.uid(), B_n5.uid()); + + levelized_file nf_B; + { + node_writer nw(nf_B); + nw << B_n7 << B_n6 << B_n5 << B_n4 << B_n3 << B_n2 << B_n1; + } - describe(".setup_next_level(...) + .[has_]current_level() + ", [&]() { - it("has no levels for 'F' terminal", []() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(false); - } + describe(".setup_next_level(...) + .[has_]current_level() + ", [&]() { + it("has no levels for 'F' terminal", []() { + levelized_file nf; + { + node_writer nw(nf); + nw << node(false); + } - node_random_access nra(nf); + node_random_access nra(nf); - AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.has_next_level(), Is().False()); + AssertThat(nra.has_current_level(), Is().False()); + AssertThat(nra.has_next_level(), Is().False()); - nra.setup_next_level(0u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(0u)); - AssertThat(nra.has_next_level(), Is().False()); + nra.setup_next_level(0u); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(0u)); + AssertThat(nra.has_next_level(), Is().False()); - nra.setup_next_level(2u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(2u)); - AssertThat(nra.has_next_level(), Is().False()); - }); + nra.setup_next_level(2u); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(2u)); + AssertThat(nra.has_next_level(), Is().False()); + }); - it("has no levels for 'T' terminal", []() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(true); - } + it("has no levels for 'T' terminal", []() { + levelized_file nf; + { + node_writer nw(nf); + nw << node(true); + } - node_random_access nra(nf); + node_random_access nra(nf); - AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.has_next_level(), Is().False()); + AssertThat(nra.has_current_level(), Is().False()); + AssertThat(nra.has_next_level(), Is().False()); - nra.setup_next_level(0u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(0u)); - AssertThat(nra.has_next_level(), Is().False()); + nra.setup_next_level(0u); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(0u)); + AssertThat(nra.has_next_level(), Is().False()); - nra.setup_next_level(1u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(1u)); - AssertThat(nra.has_next_level(), Is().False()); - }); + nra.setup_next_level(1u); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(1u)); + AssertThat(nra.has_next_level(), Is().False()); + }); - it("has empty levels before root of 'x1'", [&]() { - node_random_access nra(nf_A); + it("has empty levels before root of 'x1'", [&]() { + node_random_access nra(nf_A); - AssertThat(nra.has_current_level(), Is().False()); + AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(1u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(1u)); - nra.setup_next_level(0u); + nra.setup_next_level(0u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(0u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(0u)); - AssertThat(nra.empty_level(), Is().True()); + AssertThat(nra.empty_level(), Is().True()); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(1u)); - }); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(1u)); + }); - it("has empty levels after having skipped content of 'x1'", [&]() { - node_random_access nra(nf_A); + it("has empty levels after having skipped content of 'x1'", [&]() { + node_random_access nra(nf_A); - AssertThat(nra.has_current_level(), Is().False()); + AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.empty_level(), Is().True()); + AssertThat(nra.empty_level(), Is().True()); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(1u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(1u)); - nra.setup_next_level(2u); + nra.setup_next_level(2u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(2u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(2u)); - AssertThat(nra.empty_level(), Is().True()); + AssertThat(nra.empty_level(), Is().True()); - AssertThat(nra.has_next_level(), Is().False()); - }); + AssertThat(nra.has_next_level(), Is().False()); + }); - it("sets up the first default 'next' level to be the root", [&]() { - node_random_access nra(nf_B); + it("sets up the first default 'next' level to be the root", [&]() { + node_random_access nra(nf_B); - AssertThat(nra.has_current_level(), Is().False()); + AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(0u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(0u)); - nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(0u)); + nra.setup_next_level(); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(0u)); - AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.current_width(), Is().EqualTo(1u)); - }); + AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.current_width(), Is().EqualTo(1u)); + }); - it("sets up consecutive default 'next' level to be the non-empty levels", [&]() { - node_random_access nra(nf_B); + it("sets up consecutive default 'next' level to be the non-empty levels", [&]() { + node_random_access nra(nf_B); - AssertThat(nra.has_current_level(), Is().False()); + AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(0u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(0u)); - nra.setup_next_level(); + nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(0u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(0u)); - AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.current_width(), Is().EqualTo(1u)); + AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.current_width(), Is().EqualTo(1u)); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(1u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(1u)); - nra.setup_next_level(); + nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(1u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(1u)); - AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.current_width(), Is().EqualTo(1u)); + AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.current_width(), Is().EqualTo(1u)); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(2u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(2u)); - nra.setup_next_level(); + nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(2u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(2u)); - AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.current_width(), Is().EqualTo(3u)); + AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.current_width(), Is().EqualTo(3u)); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(4u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(4u)); - nra.setup_next_level(); + nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(4u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(4u)); - AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.current_width(), Is().EqualTo(2u)); + AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.current_width(), Is().EqualTo(2u)); - AssertThat(nra.has_next_level(), Is().False()); - }); + AssertThat(nra.has_next_level(), Is().False()); + }); - it("can go to empty level in-between non-empty ones", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(3u); + it("can go to empty level in-between non-empty ones", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(3u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(3u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(3u)); - AssertThat(nra.empty_level(), Is().True()); + AssertThat(nra.empty_level(), Is().True()); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(4u)); - }); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(4u)); + }); - it("can go from empty level to the next non-empty one", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(3u); + it("can go from empty level to the next non-empty one", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(3u); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(4u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(4u)); - nra.setup_next_level(); + nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(4u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(4u)); - AssertThat(nra.empty_level(), Is().False()); - }); + AssertThat(nra.empty_level(), Is().False()); }); + }); - describe(".at(...)", [&]() { - it("provides random access to root level of 'x1'", [&]() { - node_random_access nra(nf_A); - - AssertThat(nra.has_current_level(), Is().False()); - - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(1u)); + describe(".at(...)", [&]() { + it("provides random access to root level of 'x1'", [&]() { + node_random_access nra(nf_A); - nra.setup_next_level(1u); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(1u)); + AssertThat(nra.has_current_level(), Is().False()); - AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.current_width(), Is().EqualTo(1u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(1u)); - AssertThat(nra.at(0u), Is().EqualTo(A_n1)); - AssertThat(nra.at(A_n1.uid()), Is().EqualTo(A_n1)); + nra.setup_next_level(1u); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(1u)); - AssertThat(nra.has_next_level(), Is().False()); - }); + AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.current_width(), Is().EqualTo(1u)); - it("provides random access to root [idx]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(0u); + AssertThat(nra.at(0u), Is().EqualTo(A_n1)); + AssertThat(nra.at(A_n1.uid()), Is().EqualTo(A_n1)); - AssertThat(nra.at(0u), Is().EqualTo(B_n1)); - }); + AssertThat(nra.has_next_level(), Is().False()); + }); - it("provides random access to root [uid]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(0u); + it("provides random access to root [idx]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(0u); - AssertThat(nra.at(B_n1.uid()), Is().EqualTo(B_n1)); - }); + AssertThat(nra.at(0u), Is().EqualTo(B_n1)); + }); - it("provides random access to non-root single-node level [idx]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(1u); + it("provides random access to root [uid]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(0u); - AssertThat(nra.at(0u), Is().EqualTo(B_n2)); - }); + AssertThat(nra.at(B_n1.uid()), Is().EqualTo(B_n1)); + }); - it("provides random access to non-root single-node level [uid]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(1u); + it("provides random access to non-root single-node level [idx]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(1u); - AssertThat(nra.at(B_n2.uid()), Is().EqualTo(B_n2)); - }); + AssertThat(nra.at(0u), Is().EqualTo(B_n2)); + }); - it("provides in-order access to multi-node level [idx]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides random access to non-root single-node level [uid]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(1u); - AssertThat(nra.at(0u), Is().EqualTo(B_n3)); - AssertThat(nra.at(1u), Is().EqualTo(B_n4)); - AssertThat(nra.at(2u), Is().EqualTo(B_n5)); - }); + AssertThat(nra.at(B_n2.uid()), Is().EqualTo(B_n2)); + }); - it("provides in-order access to multi-node level [uid]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides in-order access to multi-node level [idx]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); - AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); - AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); - AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); - }); + AssertThat(nra.at(0u), Is().EqualTo(B_n3)); + AssertThat(nra.at(1u), Is().EqualTo(B_n4)); + AssertThat(nra.at(2u), Is().EqualTo(B_n5)); + }); - it("allows skipping over nodes on multi-node level [idx]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides in-order access to multi-node level [uid]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); - AssertThat(nra.at(1u), Is().EqualTo(B_n4)); - }); + AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); + AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); + }); - it("provides in-order random access to multi-node level [uid]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("allows skipping over nodes on multi-node level [idx]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); - AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); - }); + AssertThat(nra.at(1u), Is().EqualTo(B_n4)); + }); - it("provides out-of-order random access to multi-node level [idx]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides in-order random access to multi-node level [uid]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); - AssertThat(nra.at(2u), Is().EqualTo(B_n5)); - AssertThat(nra.at(0u), Is().EqualTo(B_n3)); - AssertThat(nra.at(1u), Is().EqualTo(B_n4)); - }); + AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); + }); - it("provides out-of-order random access to multi-node level [uid]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides out-of-order random access to multi-node level [idx]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); - AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); - AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); - AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); - }); + AssertThat(nra.at(2u), Is().EqualTo(B_n5)); + AssertThat(nra.at(0u), Is().EqualTo(B_n3)); + AssertThat(nra.at(1u), Is().EqualTo(B_n4)); + }); - it("provides recurring out-of-order random access to multi-node level [idx]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides out-of-order random access to multi-node level [uid]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); - AssertThat(nra.at(0u), Is().EqualTo(B_n3)); - AssertThat(nra.at(2u), Is().EqualTo(B_n5)); - AssertThat(nra.at(1u), Is().EqualTo(B_n4)); - AssertThat(nra.at(0u), Is().EqualTo(B_n3)); - AssertThat(nra.at(2u), Is().EqualTo(B_n5)); - AssertThat(nra.at(0u), Is().EqualTo(B_n3)); - AssertThat(nra.at(1u), Is().EqualTo(B_n4)); - }); + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); + AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); + AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); + }); - it("provides recurring out-of-order random access to multi-node level [uid]", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); + it("provides recurring out-of-order random access to multi-node level [idx]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); + + AssertThat(nra.at(0u), Is().EqualTo(B_n3)); + AssertThat(nra.at(2u), Is().EqualTo(B_n5)); + AssertThat(nra.at(1u), Is().EqualTo(B_n4)); + AssertThat(nra.at(0u), Is().EqualTo(B_n3)); + AssertThat(nra.at(2u), Is().EqualTo(B_n5)); + AssertThat(nra.at(0u), Is().EqualTo(B_n3)); + AssertThat(nra.at(1u), Is().EqualTo(B_n4)); + }); - AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); - AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); - AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); - AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); - AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); - AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); - AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); - }); + it("provides recurring out-of-order random access to multi-node level [uid]", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); + + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); + AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); + AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); + AssertThat(nra.at(B_n5.uid()), Is().EqualTo(B_n5)); + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); + AssertThat(nra.at(B_n4.uid()), Is().EqualTo(B_n4)); + }); - it("provides access after having gone by default from an empty level", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(3u); + it("provides access after having gone by default from an empty level", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(3u); - AssertThat(nra.has_next_level(), Is().True()); - AssertThat(nra.next_level(), Is().EqualTo(4u)); + AssertThat(nra.has_next_level(), Is().True()); + AssertThat(nra.next_level(), Is().EqualTo(4u)); - nra.setup_next_level(); + nra.setup_next_level(); - AssertThat(nra.has_current_level(), Is().True()); - AssertThat(nra.current_level(), Is().EqualTo(4u)); + AssertThat(nra.has_current_level(), Is().True()); + AssertThat(nra.current_level(), Is().EqualTo(4u)); - AssertThat(nra.empty_level(), Is().False()); + AssertThat(nra.empty_level(), Is().False()); - AssertThat(nra.at(B_n7.uid()), Is().EqualTo(B_n7)); - AssertThat(nra.at(B_n6.uid()), Is().EqualTo(B_n6)); - AssertThat(nra.at(B_n6.uid()), Is().EqualTo(B_n6)); - AssertThat(nra.at(B_n7.uid()), Is().EqualTo(B_n7)); - }); + AssertThat(nra.at(B_n7.uid()), Is().EqualTo(B_n7)); + AssertThat(nra.at(B_n6.uid()), Is().EqualTo(B_n6)); + AssertThat(nra.at(B_n6.uid()), Is().EqualTo(B_n6)); + AssertThat(nra.at(B_n7.uid()), Is().EqualTo(B_n7)); }); + }); - describe(".root()", [&]() { - it("provides root for 'F' terminal", []() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(false); - } + describe(".root()", [&]() { + it("provides root for 'F' terminal", []() { + levelized_file nf; + { + node_writer nw(nf); + nw << node(false); + } - node_random_access nra(nf); + node_random_access nra(nf); - AssertThat(nra.root(), Is().EqualTo(node::pointer_type(false))); - }); + AssertThat(nra.root(), Is().EqualTo(node::pointer_type(false))); + }); - it("provides root for 'T' terminal", []() { - levelized_file nf; - { - node_writer nw(nf); - nw << node(true); - } + it("provides root for 'T' terminal", []() { + levelized_file nf; + { + node_writer nw(nf); + nw << node(true); + } - node_random_access nra(nf); + node_random_access nra(nf); - AssertThat(nra.root(), Is().EqualTo(node::pointer_type(true))); - }); + AssertThat(nra.root(), Is().EqualTo(node::pointer_type(true))); + }); - it("provides root before accessing anything", [&]() { - node_random_access nra(nf_B); + it("provides root before accessing anything", [&]() { + node_random_access nra(nf_B); - AssertThat(nra.root(), Is().EqualTo(B_n1.uid())); - }); + AssertThat(nra.root(), Is().EqualTo(B_n1.uid())); + }); - it("provides root after accessing node below it", [&]() { - node_random_access nra(nf_B); - nra.setup_next_level(2u); - AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); + it("provides root after accessing node below it", [&]() { + node_random_access nra(nf_B); + nra.setup_next_level(2u); + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(B_n3)); - AssertThat(nra.root(), Is().EqualTo(B_n1.uid())); - }); + AssertThat(nra.root(), Is().EqualTo(B_n1.uid())); }); - - // TODO: reverse }); + + // TODO: reverse }); }); }); From fdf41b4791941a089401f3999fd43c189c1d0d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 10:48:55 +0200 Subject: [PATCH 11/30] Add TODO for better responsibility/performance Currently, every stream can be negated and so it ends up adding lots of conditional statements where none is necessary. Hence, if we move the '_negate' test into 'node_stream' only, then we can regain some performance --- src/adiar/internal/io/node_stream.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/adiar/internal/io/node_stream.h b/src/adiar/internal/io/node_stream.h index 9c46ca8be..44bb0e931 100644 --- a/src/adiar/internal/io/node_stream.h +++ b/src/adiar/internal/io/node_stream.h @@ -15,6 +15,8 @@ namespace adiar::internal /// nodes within the file). /// /// \see shared_levelized_file + // + // TODO: Move '!' negation out of 'file_stream', 'levelized_file_stream', and instead in here! ////////////////////////////////////////////////////////////////////////////////////////////////// template class node_stream : public levelized_file_stream From 8503ad868f181d97ad7b1a0202015ce0fd5d2182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 11:27:20 +0200 Subject: [PATCH 12/30] Fill and Extend comments in --- src/adiar/internal/io/arc_writer.h | 61 +++--- src/adiar/internal/io/file.h | 155 +++++++-------- src/adiar/internal/io/file_writer.h | 93 +++++---- src/adiar/internal/io/levelized_file.h | 187 +++++++++--------- src/adiar/internal/io/levelized_file_writer.h | 104 +++++----- src/adiar/internal/io/shared_file_ptr.h | 119 ++++++----- 6 files changed, 352 insertions(+), 367 deletions(-) diff --git a/src/adiar/internal/io/arc_writer.h b/src/adiar/internal/io/arc_writer.h index 8102b6924..a5bb13008 100644 --- a/src/adiar/internal/io/arc_writer.h +++ b/src/adiar/internal/io/arc_writer.h @@ -9,11 +9,11 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Writer for a set of arcs. /// /// \see shared_levelized_file - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// class arc_writer : public levelized_file_writer { private: @@ -29,38 +29,38 @@ namespace adiar::internal file_traits::idx__terminals__out_of_order; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct unattached to any levelized arc file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// arc_writer() : levelized_file_writer() {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a levelized arc file. /// /// \pre The file is empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// arc_writer(levelized_file& af) : levelized_file_writer() { attach(af); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a shared levelized arc file. /// /// \pre The file is empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// arc_writer(shared_ptr> af) : levelized_file_writer() { attach(af); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches and cleans up from the levelized file (if need be). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// ~arc_writer() { // Sort the out-of-order terminals with 'detach()'. @@ -68,15 +68,14 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a levelized file of arcs. /// - /// \warning Since ownership is \em not shared with this writer, you have to - /// ensure, that the file in question is not destructed before - /// `.detach()` is called. + /// \warning Since ownership is \em not shared with this writer, you have to ensure, that the + /// file in question is not destructed before `.detach()` is called. /// /// \pre The file is empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(levelized_file& af) { @@ -88,11 +87,11 @@ namespace adiar::internal return levelized_file_writer::attach(af); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a shared levelized file of arcs. /// /// \pre The file is empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(shared_ptr>& af) { @@ -104,9 +103,9 @@ namespace adiar::internal return levelized_file_writer::attach(af); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches after having sort the out-of-order terminals. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// void detach() { @@ -121,13 +120,13 @@ namespace adiar::internal levelized_file_writer::detach(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Write directly to the level_info file. /// /// \param li Level information to push. /// /// \pre `attached() == true`. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// void push(const level_info& li) { @@ -138,13 +137,13 @@ namespace adiar::internal levelized_file_writer::push(li); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Write directly to the level_info file. /// /// \param li Level information to push. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// arc_writer& operator<<(const level_info& li) { @@ -152,7 +151,7 @@ namespace adiar::internal return *this; } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Push an arc to the relevant underlying file. /// /// \param a An arc with `a.target() != a::pointer_type::nil`. @@ -160,7 +159,7 @@ namespace adiar::internal /// \pre `attached() == true`. /// /// \see unsafe_push_internal unsafe_push_terminal - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// void push(const arc& a) { @@ -172,11 +171,11 @@ namespace adiar::internal } } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Push an ac to the relevant underlying file. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// arc_writer& operator<<(const arc& a) { @@ -184,11 +183,11 @@ namespace adiar::internal return *this; } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Push an internal arc to its file, i.e. where the target is a node. /// /// \pre `attached() == true`. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// void push_internal(const arc& a) { @@ -201,11 +200,11 @@ namespace adiar::internal levelized_file_writer::template push(a); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Push a terminal arc to its file, i.e. where the target is a terminal. /// /// \pre `attached() == true`. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// void push_terminal(const arc& a) { diff --git a/src/adiar/internal/io/file.h b/src/adiar/internal/io/file.h index ad3e218db..3f3b23fe8 100644 --- a/src/adiar/internal/io/file.h +++ b/src/adiar/internal/io/file.h @@ -16,65 +16,63 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// - /// \brief Provides compile-time known settings and meta information - /// variables used in `file` and - /// `levelized_file`. + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Provides compile-time known settings and meta information variables used in + /// `file` and `levelized_file`. /// - /// \details Files also contain various pieces of meta information. Instead of - /// creating a larger object-oriented hierarchy, we provide this - /// `file_traits` template to provide at compile-time the settings - /// and meta information to include. + /// \details Files also contain various pieces of meta information. Instead of creating a larger + /// object-oriented hierarchy, we provide this `file_traits` template to provide at + /// compile-time the settings and meta information to include. /// - /// \param T Element type in the file. - ////////////////////////////////////////////////////////////////////////////// + /// \tparam T + /// Element type in the file. + ////////////////////////////////////////////////////////////////////////////////////////////////// template struct file_traits; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief A file on disk. /// - /// \details A shallow wrapper TPIE's temp_file class to ensure the - /// file's content is part of the type and to provide auxiliary - /// functions. + /// \details A shallow wrapper TPIE's temp_file class to ensure the file's content is + /// part of the type and to provide auxiliary functions. /// - /// \tparam T Type of the file's content. - ////////////////////////////////////////////////////////////////////////////// + /// \tparam T + /// Type of the file's content. + ////////////////////////////////////////////////////////////////////////////////////////////////// template // <-- Header class file // : public file_traits::stats { public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file's elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using value_type = T; static_assert(std::is_pod::value, "File content must be a POD"); private: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Access flags to be used privately within reader's and writers. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using access_type = tpie::access_type; static constexpr access_type read_access = tpie::access_type::access_read; static constexpr access_type write_access = tpie::access_type::access_write; private: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The underlying TPIE file /// - /// \remark This variable is made 'mutable' to allow it to be used with - // 'non-const' operations (opening a read-only stream) in a 'const' - // context. - //////////////////////////////////////////////////////////////////////////// + /// \remark This variable is made 'mutable' to allow it to be used with 'non-const' operations + // (opening a read-only stream) in a 'const' context. + //////////////////////////////////////////////////////////////////////////////////////////////// mutable tpie::temp_file _tpie_file; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // TODO: atomic read-write counter? - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Befriend the few places that need direct access to these variables. template friend class file_stream; @@ -90,20 +88,19 @@ namespace adiar::internal friend class levelized_file_writer; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Constructor for a new unammed \em temporary file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file() : _tpie_file() {} public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Constructor for a prior named \em persisted file. /// - /// \throws runtime_error If the path does not point to an \em existing file - /// on disk. - //////////////////////////////////////////////////////////////////////////// + /// \throws runtime_error If the path does not point to an \em existing file on disk. + //////////////////////////////////////////////////////////////////////////////////////////////// file(const std::string& path) : _tpie_file(path, true) { @@ -111,12 +108,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Whether this file is persistent or temporary, i.e. the file on - /// disk will \em not be removed when this object is destructed. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Whether this file is persistent or temporary, i.e. the file on disk will \em not be + /// removed when this object is destructed. /// /// \see make_persistent - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool is_persistent() const { @@ -124,12 +121,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Make the file persistent: if the `file<>` object is destructed, - /// the physical file on disk will not be deleted. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Make the file persistent: if the `file<>` object is destructed, the physical file on + /// disk will not be deleted. /// /// \see is_persistent - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void make_persistent() { @@ -138,9 +135,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \copydoc is_persistent - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool is_temp() const { @@ -148,11 +145,11 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the file actually exists on disk. /// /// \see path - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool exists() const { @@ -160,9 +157,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of elements in the file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size() const { @@ -174,9 +171,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the file is empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool empty() const { @@ -195,9 +192,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Creates the file on disk, if it does not yet exist. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void touch() { @@ -205,32 +202,32 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Get the size of the file header. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // static size_t header_size() constexpr //{ TODO } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Set the contents of the file header. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // void set_header(const std::string &p) //{ TODO } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Get the contents of the file header. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // header_t get_header() const //{ TODO } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the path for this file. /// /// \see exists move - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const std::string& path() const { @@ -238,9 +235,9 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Set the path for this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void set_path(const std::string& p) { @@ -248,9 +245,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether this file can be moved. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool can_move() { @@ -258,19 +255,18 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Move file from one place to another. /// /// \param new_path Path to move the file to. /// - /// \pre `can_move()`and `new_path` names a yet non-existing file. Neither - /// should any `file_stream`s or `file_writer`s be hooked into this - /// file. + /// \pre `can_move()`and `new_path` names a yet non-existing file. Neither should any + /// `file_stream`s or `file_writer`s be hooked into this file. /// /// \throws runtime_error Preconditions are violated /// /// \throws runtime_error Moving the file is unsuccessful. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void move(const std::string& new_path) { @@ -295,8 +291,8 @@ namespace adiar::internal if (!std::filesystem::exists(path())) { throw static_cast(e1); } try { - // Most likely, this catch-case is an "Invalid cross-device link": - // try to copy-delete it instead in O(N) time. + // Most likely, this catch-case is an "Invalid cross-device link": try to copy-delete it + // instead in O(N) time. std::filesystem::copy(path(), new_path); std::filesystem::remove(path()); } catch (std::filesystem::filesystem_error& e2) { @@ -309,18 +305,17 @@ namespace adiar::internal } } - // Set the path on the TPIE object (which does not attempt to delete the - // old path). + // Set the path on the TPIE object (which does not attempt to delete the old path). set_path(new_path); } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Sort the content of this file in relation to a given predicate. /// - /// \pre `is_persistent() == false` and `file_stream` nor `file_writer` is - /// attached to this file. - //////////////////////////////////////////////////////////////////////////// + /// \pre `is_persistent() == false` and `file_stream` nor `file_writer` is attached to this + /// file. + //////////////////////////////////////////////////////////////////////////////////////////////// template > void sort(pred_t pred = pred_t()) @@ -340,12 +335,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create a copy of a file. /// - /// \remark This new file is a temporary file and must be marked persisted - /// to be kept existing beyond the object's lifetime. - //////////////////////////////////////////////////////////////////////////// + /// \remark This new file is a temporary file and must be marked persisted to be kept existing + /// beyond the object's lifetime. + //////////////////////////////////////////////////////////////////////////////////////////////// static file copy(const file& f) { diff --git a/src/adiar/internal/io/file_writer.h b/src/adiar/internal/io/file_writer.h index 365894142..c0dbd638c 100644 --- a/src/adiar/internal/io/file_writer.h +++ b/src/adiar/internal/io/file_writer.h @@ -12,16 +12,15 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// - /// \brief Write-only access to a simple file including a consistency check - /// on the given input. + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Write-only access to a simple file including a consistency check on the given input. /// - /// \tparam value_t Type of the file's content. + /// \tparam T + /// Type of the file's content. /// - /// \details The consistency check verifies, whether something is allowed to - /// come after something else. In all our current use-cases, the - /// check induces a total ordering. - ////////////////////////////////////////////////////////////////////////////// + /// \details The consistency check verifies, whether something is allowed to come after something + /// else. In all our current use-cases, the check induces a total ordering. + ////////////////////////////////////////////////////////////////////////////////////////////////// template class file_writer { @@ -36,55 +35,54 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// - /// \brief If attached to a shared file then hook into the reference - /// counting such that the file is not garbage collected while we - /// write to it. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief If attached to a shared file then hook into the reference counting such that the file + /// is not garbage collected while we write to it. + //////////////////////////////////////////////////////////////////////////////////////////////// shared_ptr _file_ptr; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief TPIE's file stream object to write elements with. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// tpie::file_stream _stream; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct unattached to any file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_writer() {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given `file`. /// /// \pre No `file_stream` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_writer(file& f) { attach(f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given shared `file`. /// /// \pre No `file_stream` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_writer(adiar::shared_ptr>& f) { attach(f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches and cleans up when destructed. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// ~file_writer() { detach(); } protected: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(file& f, adiar::shared_ptr p) { @@ -97,50 +95,49 @@ namespace adiar::internal _stream.seek(0, tpie::file_stream_base::end); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Befriend the few places that need direct access to the above 'attach'. template friend class levelized_file_writer; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a file. /// /// \pre No `file_stream` is currently attached to this file. /// - /// \warning Since ownership is \em not shared with this writer, you have to - /// ensure, that the file in question is not destructed before - /// `.detach()` is called. - //////////////////////////////////////////////////////////////////////////// + /// \warning Since ownership is \em not shared with this writer, you have to ensure, that the + /// file in question is not destructed before `.detach()` is called. + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(file& f) { attach(f, nullptr); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a shared file. /// /// \pre No `file_stream` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(adiar::shared_ptr> f) { attach(*f, f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the writer currently is attached to any file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool attached() const { return _stream.is_open(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detach from a file (if need be). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void detach() { @@ -148,22 +145,22 @@ namespace adiar::internal if (_file_ptr) { _file_ptr.reset(); } } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Push an element to the end of the file. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void push(const value_type& e) { _stream.write(e); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Push an element to the end of the file. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_writer& operator<<(const value_type& e) { @@ -171,44 +168,44 @@ namespace adiar::internal return *this; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether anything has been pushed the file. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool has_pushed() const { return _stream.size() > 0; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the underlying file is empty. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool empty() const { return !has_pushed(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of elements written to this file. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size() const { return _stream.size(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Sort the content of the attached file. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template > void sort(const pred_t pred = pred_t()) diff --git a/src/adiar/internal/io/levelized_file.h b/src/adiar/internal/io/levelized_file.h index 50358084f..dae52d45e 100644 --- a/src/adiar/internal/io/levelized_file.h +++ b/src/adiar/internal/io/levelized_file.h @@ -16,54 +16,53 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief File representing a (levelized) DAG. /// - /// \param T Type of the file's content. + /// \tparam T + /// Type of the file's content. /// - /// \param SplitOnLevels Whether each file type should be split in a file - /// per level. Doing so provides support for even - /// larger decision diagrams and a variable swapping - /// operation. + /// \tparam SplitOnLevels + /// Whether each file type should be split in a file per level. Doing so provides support for + /// even larger decision diagrams and a variable swapping operation. /// - /// \details The entities of Adiar that represents DAGs are represented by one - /// or more files of type `elem_type`. To optimise several - /// algorithms, these files also carry around 'meta' information. - /// This information is stored in the variables and in a levelized + /// \details The entities of Adiar that represents DAGs are represented by one or more files of + /// type `elem_type`. To optimise several algorithms, these files also carry around + /// 'meta' information. This information is stored in the variables and in a levelized /// fashion depending on the granularity of the information. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class levelized_file; - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Files that combined represent a DAG. /// - /// \param T Type of the file's content. - //////////////////////////////////////////////////////////////////////////// + /// \tparam T Type of the file's content. + ////////////////////////////////////////////////////////////////////////////////////////////////// template class levelized_file : public file_traits::stats { public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file's elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using value_type = T; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of files to collectively represent a DAG. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static constexpr size_t FILES = file_traits::files; static_assert(0 < FILES, "The number of files must be positive"); private: - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// inline void throw_if_bad_idx(const size_t idx) const { if (FILES <= idx) throw out_of_range("Index must be within interval [0;FILES-1]"); } - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// inline void throw_if_persistent() const { @@ -71,9 +70,9 @@ namespace adiar::internal } private: - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Derives the canonical path for one of the file. - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static std::string canonical_file_path(const std::string& path_prefix, const size_t idx) { @@ -82,9 +81,9 @@ namespace adiar::internal return ss.str(); } - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Derives the canonical path for the level information file. - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static std::string canonical_levels_path(const std::string& path_prefix) { @@ -94,24 +93,23 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Meta information on a level by level granularity. - //////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// file _level_info_file; - //////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Files describing the directed acyclic graph. - //////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////////// file _files[FILES]; - //////////////////////////////////////////////////////////////////////////// - /// \brief Whether the file paths in '_level_info_file' and '_files' are - /// canonical, i.e. match the paths created by `canonical_file_path` - /// and `canonical_levels_path`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Whether the file paths in '_level_info_file' and '_files' are canonical, i.e. match + /// the paths created by `canonical_file_path` and `canonical_levels_path`. + //////////////////////////////////////////////////////////////////////////////////////////////// bool _canonical_paths = false; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Befriend the few places that need direct access to these variables. template friend class levelized_file_stream; @@ -123,26 +121,25 @@ namespace adiar::internal friend class level_info_stream; private: - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Copy of file statistics but without its content. - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file(const typename file_traits::stats& o) : file_traits::stats(o) {} public: - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Constructor for a new unamed \em temporary file. - /////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file() {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Constructor for a prior named \em persisted file. /// - /// \throws runtime_error If one or more files are missing in relation - /// to the given path-prefix. - //////////////////////////////////////////////////////////////////////////// + /// \throws runtime_error If one or more files are missing in relation to the given path-prefix. + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file(const std::string path_prefix) { // Set up '_files[idx]' @@ -179,12 +176,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Whether the file(s) are persistent or temporary, i.e. the file(s) - /// on disk will \em not be removed when this object is destructed. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Whether the file(s) are persistent or temporary, i.e. the file(s) on disk will \em + /// not be removed when this object is destructed. /// /// \see make_persistent - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool is_persistent() const { @@ -198,16 +195,16 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Make the file(s) persistent: if the `file<>` object is later - /// destructed, the physical file on disk will not be deleted. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Make the file(s) persistent: if the `file<>` object is later destructed, the physical + /// file on disk will not be deleted. /// /// \pre `canonical_paths() == true` (use `move()` to make them so). /// /// \throws runtime_error If `canonical_paths() == false`. /// /// \see is_persistent, canonical_paths, move - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void make_persistent() { @@ -219,10 +216,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Make the file(s) persistent at a given path: if the `file<>` - /// object is later destructed, the physical file on disk will not be - /// deleted. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Make the file(s) persistent at a given path: if the `file<>` object is later + /// destructed, the physical file on disk will not be deleted. /// /// \pre `can_move() == true` /// @@ -230,7 +226,7 @@ namespace adiar::internal /// `move(path_prefix)` operation fails. /// /// \see is_persistent, move - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void make_persistent(const std::string& path_prefix) { @@ -239,9 +235,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \copydoc is_persistent - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool is_temp() const { @@ -249,11 +245,11 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the file(s) actually exists on disk. /// /// \see path - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool exists() const { @@ -268,9 +264,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The number of elements in a specific file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size(const size_t idx) const { @@ -279,9 +275,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The number of elements in the file(s). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size() const { @@ -291,9 +287,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The number of elements in the levelized meta information file - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t levels() const { @@ -301,11 +297,11 @@ namespace adiar::internal } public: - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The first level to be encountered, i.e. the last level pushed. /// /// \pre `levels() > 0` - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t first_level() const { @@ -314,11 +310,11 @@ namespace adiar::internal return fs.pull().level(); } - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The last level to be encountered, i.e. the first level pushed. /// /// \pre `levels() > 0` - ////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t last_level() const { @@ -328,9 +324,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether all file(s) are empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool empty() const { @@ -338,9 +334,9 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Creates the file(s) on disk, if they do not yet already do. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void __touch() const { @@ -351,9 +347,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Creates the file(s) on disk, if they do not yet already do. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void touch() { @@ -364,11 +360,11 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the paths for all files comprising this levelized file. /// /// \see exists move - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// std::array paths() const { @@ -379,9 +375,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether this file can be moved. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool can_move() { @@ -395,17 +391,17 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Move file from one place to another. /// /// \param path_prefix Prefix of the path used for the underlying files. /// - /// \pre `is_persistent() == false` (other's might depend on it) and - /// `path_prefix` names a yet non-existing file. Neither should a - /// `file_stream` nor a `file_writer` be hooked into this file. + /// \pre `is_persistent() == false` (other's might depend on it) and `path_prefix` names a yet + /// non-existing file. Neither should a `file_stream` nor a `file_writer` be hooked into + /// this file. /// /// \throws runtime_error Preconditions are violated. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void move(const std::string& path_prefix) { @@ -413,8 +409,8 @@ namespace adiar::internal // Disallow moving the files on-top of an existing path-prefix. // - // TODO: allow this? the path-prefix might be an independently created, - // but intendedly related, file made by the user. + // TODO: allow this? the path-prefix might be an independently created, but intendedly + // related, file made by the user. if (std::filesystem::exists(path_prefix)) throw runtime_error("path-prefix '" + path_prefix + "' exists."); @@ -443,13 +439,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Sort the content of one of the files in relation to a given /// predicate. /// - /// \pre `is_persistent() == false` and no stream nor writer is attached to - /// this file. - //////////////////////////////////////////////////////////////////////////// + /// \pre `is_persistent() == false` and no stream nor writer is attached to this file. + //////////////////////////////////////////////////////////////////////////////////////////////// template > void sort(size_t idx, pred_t pred = pred_t()) @@ -461,12 +456,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create a copy of a levelized file. /// - /// \remark This new file is a temporary file and must be marked persisted - /// to be kept existing beyond the object's lifetime. - //////////////////////////////////////////////////////////////////////////// + /// \remark This new file is a temporary file and must be marked persisted to be kept existing + /// beyond the object's lifetime. + //////////////////////////////////////////////////////////////////////////////////////////////// static levelized_file copy(const levelized_file& lf) { @@ -481,11 +476,11 @@ namespace adiar::internal } }; - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Files (split on each level) that combined represent a DAG. /// /// \param elem_type Type of the file's content. - //////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// // template // class levelized_file // : public file_traits::stats diff --git a/src/adiar/internal/io/levelized_file_writer.h b/src/adiar/internal/io/levelized_file_writer.h index 46e746f89..6f9653550 100644 --- a/src/adiar/internal/io/levelized_file_writer.h +++ b/src/adiar/internal/io/levelized_file_writer.h @@ -11,11 +11,11 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Writer to a set of file(s) with 'meta' information. /// /// \see node_writer arc_writer - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class levelized_file_writer { @@ -30,64 +30,63 @@ namespace adiar::internal } protected: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Pointer to update the meta information. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// adiar::shared_ptr> _file_ptr; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Writers for the file with level information. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_writer _level_writer; static constexpr size_t elem_writers = file_traits::files; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Writers for each of the files with 'value_type'. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_writer _elem_writers[elem_writers]; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct unattached to any levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_writer() {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given levelized file. /// /// \pre No file stream or other writer is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_writer(levelized_file& f) { attach(f); } //////////////////////////////////////////////////////////////////////////// - /// \brief Construct attached to a given shared levelized file. + /// \brief Construct attached to a given shared levelized file.//////////////////// /// /// \pre No file stream or other writer is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_writer(adiar::shared_ptr> f) { attach(f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches and cleans up when destructed. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// ~levelized_file_writer() {} // <-- detach within `~file_writer<...>()` public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a file. /// - /// \warning Since ownership is \em not shared with this writer, you have to - /// ensure, that the file in question is not destructed before - /// `.detach()` is called. - //////////////////////////////////////////////////////////////////////////// + /// \warning Since ownership is \em not shared with this writer, you have to ensure, that the + /// file in question is not destructed before `.detach()` is called. + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(levelized_file& f) { @@ -103,9 +102,9 @@ namespace adiar::internal _elem_writers[s_idx].attach(f._files[s_idx], nullptr); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a shared file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(adiar::shared_ptr> f) { @@ -118,9 +117,9 @@ namespace adiar::internal _elem_writers[s_idx].attach(f->_files[s_idx], f); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the writer currently is attached to a levelized file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool attached() const { @@ -134,9 +133,9 @@ namespace adiar::internal return res; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detach from a levelized file (if need be) - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void detach() { @@ -145,26 +144,28 @@ namespace adiar::internal _file_ptr.reset(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Write directly to the level_info file. /// - /// \param li Level information to push. + /// \param li + /// Level information to push. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void push(const level_info& li) { _level_writer.push(li); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Write directly to the level_info file. /// - /// \param li Level information to push. + /// \param li + /// Level information to push. /// /// \pre `attached() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// levelized_file_writer& operator<<(const level_info& li) { @@ -172,12 +173,15 @@ namespace adiar::internal return *this; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Write to one of the files. /// - /// \tparam s_idx File index to push to. - /// \param e Element to push. - //////////////////////////////////////////////////////////////////////////// + /// \tparam s_idx + /// File index to push to. + /// + /// \param e + /// Element to push. + //////////////////////////////////////////////////////////////////////////////////////////////// template void push(const value_type& e) @@ -187,10 +191,9 @@ namespace adiar::internal _elem_writers[s_idx].push(e); } - //////////////////////////////////////////////////////////////////////////// - /// \brief Number of elements written to the underlying files (excluding the - /// level info file). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Number of elements written to the underlying files (excluding the level info file). + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size(const size_t s_idx) const { @@ -198,10 +201,9 @@ namespace adiar::internal return _elem_writers[s_idx].size(); } - //////////////////////////////////////////////////////////////////////////// - /// \brief Number of elements written to the underlying files (excluding the - /// level info file). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Number of elements written to the underlying files (excluding the level info file). + //////////////////////////////////////////////////////////////////////////////////////////////// size_t size() const { @@ -210,18 +212,18 @@ namespace adiar::internal return acc; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of elements in the level info file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// size_t levels() const { return _level_writer.size(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether anything has been pushed to any of the underlying files. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool has_pushed() const { @@ -231,9 +233,9 @@ namespace adiar::internal return levels() > 0; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the underlying file is empty. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool empty() const { diff --git a/src/adiar/internal/io/shared_file_ptr.h b/src/adiar/internal/io/shared_file_ptr.h index a85cad0f0..6884d867b 100644 --- a/src/adiar/internal/io/shared_file_ptr.h +++ b/src/adiar/internal/io/shared_file_ptr.h @@ -9,136 +9,133 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// - /// \brief Provides shared ownership of a single file. This also includes - /// (thread-safe) reference counting and automatic garbage collection. + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Provides shared ownership of a single file. This also includes (thread-safe) + /// reference counting and automatic garbage collection. /// - /// \details This is a wrapper on the `adiar::shared_ptr` (which in itself is - /// just a wrapper on `std::shared_ptr`) to slightly change its - /// semantics: - /// - Default constructor creates a new fresh file rather than being - /// null (TODO: change?) - /// - If `const` then not only can the pointer not be moved, but the - /// object underneath is `const` too, i.e. read-only. + /// \details This is a wrapper on the `adiar::shared_ptr` (which in itself is just a wrapper on + /// `std::shared_ptr`) to slightly change its semantics: + /// - Default constructor creates a new fresh file rather than being null (TODO: change?) + /// - If `const` then not only can the pointer not be moved, but the object underneath is + /// `const` too, i.e. read-only. /// /// \tparam File Type of the underlying file - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class shared_file_ptr : public shared_ptr { public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file object. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using file_type = File; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file's elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using value_type = typename file_type::value_type; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Default constructor with a new fresh temporary file. /// - /// \internal This constructor is part of a larger invariant: "A shared file - /// always is in a 'valid' state". That is, an algorithm right - /// chooses to crash/throw rather than return an error value that - /// may propagate throughout computation (similar to how CUDD - /// does). If this should be changed, then all internal functions - /// should be changed to use the make_shared_file and + /// \internal This constructor is part of a larger invariant: "A shared file always is in a + /// 'valid' state". That is, an algorithm right chooses to crash/throw rather than + /// return an error value that may propagate throughout computation (similar to how + /// CUDD does). If this should be changed, then all internal functions should be + /// changed to use the make_shared_file and /// make_shared_levelized_file instead. /// /// \see make_shared_file make_shared_levelized_file - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr() : shared_ptr(adiar::make_shared()) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Constructor to reload a persisted file. /// /// \see make_shared_file make_shared_levelized_file - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr(const std::string p) : shared_ptr(adiar::make_shared(p)) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Conversion-constructor from raw `shared_ptr`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr(const shared_ptr& other) : shared_ptr(other) {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Copy-constructor. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr(const shared_file_ptr& other) = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Move-constructor. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr(shared_file_ptr&& other) = default; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr& operator=(const shared_file_ptr& o) = default; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// shared_file_ptr& operator=(shared_file_ptr&& o) = default; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the raw pointer (read-only). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const File* get() const { return shared_ptr::get(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the raw pointer. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// File* get() { return shared_ptr::get(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Dereference the pointer to obtain the file (read-only). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const File& operator*() const { return *get(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Dereference the pointer to obtain the file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// File& operator*() { return *get(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Member access (read-only) to the file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const File* operator->() const { return get(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Member access for the underlying file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// File* operator->() { @@ -146,12 +143,12 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create a copy of a shared file. /// - /// \remark This new file is a temporary file and must be marked persisted - /// to be kept existing beyond the last reference to it is gone. - //////////////////////////////////////////////////////////////////////////// + /// \remark This new file is a temporary file and must be marked persisted to be kept existing + /// beyond the last reference to it is gone. + //////////////////////////////////////////////////////////////////////////////////////////////// static shared_file_ptr copy(const shared_file_ptr& f) { @@ -159,15 +156,15 @@ namespace adiar::internal } }; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Shared ownership of a file containing elements of the given type. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template using shared_file = shared_file_ptr>; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Creates a new (temporary) file with shared ownership. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template inline shared_file make_shared_file() @@ -175,9 +172,9 @@ namespace adiar::internal return adiar::make_shared>(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Open a persisted file with shared ownership. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template inline shared_file make_shared_file(const std::string& p) @@ -185,15 +182,15 @@ namespace adiar::internal return adiar::make_shared>(p); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Shared ownership of a levelized file. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template using shared_levelized_file = shared_file_ptr>; - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Creates a new (temporary) levelized file with shared ownership. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template inline shared_levelized_file make_shared_levelized_file() @@ -201,9 +198,9 @@ namespace adiar::internal return adiar::make_shared>(); } - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Open a persisted file with shared ownership. - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template inline shared_levelized_file make_shared_levelized_file(const std::string& p) From 511856faff1de0638943f833a530eabadf978bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 11:29:08 +0200 Subject: [PATCH 13/30] Extend comments in to column 100 --- src/adiar/internal/dd_func.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/adiar/internal/dd_func.h b/src/adiar/internal/dd_func.h index 46bdb3169..560419f9d 100644 --- a/src/adiar/internal/dd_func.h +++ b/src/adiar/internal/dd_func.h @@ -111,9 +111,9 @@ namespace adiar::internal return dd->last_level(); } - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of nodes in a decision diagram. - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template size_t dd_nodecount(const DD& dd) @@ -121,9 +121,9 @@ namespace adiar::internal return dd_isterminal(dd) ? 0u : dd->size(); } - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of variables, i.e. levels, present in a decision diagram. - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template typename DD::label_type dd_varcount(const DD& dd) @@ -131,9 +131,9 @@ namespace adiar::internal return dd->levels(); } - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of nodes on the widest level of a decision diagram. - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template size_t dd_width(const DD& dd) @@ -141,9 +141,9 @@ namespace adiar::internal return dd.width(); } - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief The variable labels (in order of their level) that are present in a decision diagram. - //////////////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template void dd_support(const DD& dd, const consumer& cb) From f0380493882c30a7f576b911c3f08fb6023fcf25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 11:33:07 +0200 Subject: [PATCH 14/30] Clean-up of code to auto-detect 'replace_type' --- src/adiar/internal/algorithms/replace.h | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/adiar/internal/algorithms/replace.h b/src/adiar/internal/algorithms/replace.h index 484eca5dd..fb73fd290 100644 --- a/src/adiar/internal/algorithms/replace.h +++ b/src/adiar/internal/algorithms/replace.h @@ -74,27 +74,31 @@ namespace adiar::internal label_type prev_before = Policy::max_label + 1; label_type prev_after = Policy::max_label + 1; while (ls.can_pull()) { - const label_type next_before = ls.pull().level(); - const result_type next_after = m(next_before); + const label_type next_before = ls.pull().level(); + const result_type next_after_opt = m(next_before); if constexpr (is_partial_map) { - if (!next_after.has_value()) { continue; } + if (!next_after_opt.has_value()) { continue; } + } + + label_type next_after; + if constexpr (is_partial_map) { + if (!next_after_opt.has_value()) { continue; } + next_after = *next_after_opt; + } else { + next_after = next_after_opt; } identity &= next_before == next_after; monotone &= Policy::max_label < prev_before || prev_after < next_after; prev_before = next_before; - if constexpr (is_partial_map) { - prev_after = *next_after; - } else { - prev_after = next_after; - } + prev_after = next_after; } - if (identity) { return replace_type::Identity; } - if (monotone) { return replace_type::Monotone; } - return replace_type::Non_Monotone; + if (!monotone) { return replace_type::Non_Monotone; } + if (!identity) { return replace_type::Monotone; } + return replace_type::Identity; } ////////////////////////////////////////////////////////////////////////////////////////////////// From 4a65c229b07befe71cdea915bcca0b889d44e0d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 11:42:11 +0200 Subject: [PATCH 15/30] Swap order of member functions --- src/adiar/internal/dd.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/adiar/internal/dd.h b/src/adiar/internal/dd.h index e07c3c417..693eb83bc 100644 --- a/src/adiar/internal/dd.h +++ b/src/adiar/internal/dd.h @@ -355,15 +355,6 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// public: - //////////////////////////////////////////////////////////////////////////////////////////////// - /// \brief Read-only access to the negation flag. - //////////////////////////////////////////////////////////////////////////////////////////////// - bool - is_negated() const - { - return this->_negate; - } - //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Read-only access to the raw files and meta information. //////////////////////////////////////////////////////////////////////////////////////////////// @@ -383,6 +374,15 @@ namespace adiar::internal return this->_file.get(); } + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Read-only access to the negation flag. + //////////////////////////////////////////////////////////////////////////////////////////////// + bool + is_negated() const + { + return this->_negate; + } + /// \cond //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the 1-level cut of the desired type, i.e. of the sub-graph including the From 79461599b05013c68434c6b6e8564977178f7328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 13:33:41 +0200 Subject: [PATCH 16/30] Clean up 'level_merger' and add missing unit tests --- .../internal/data_structures/level_merger.h | 14 +- .../data_structures/test_level_merger.cpp | 202 ++++++++++++++++-- 2 files changed, 195 insertions(+), 21 deletions(-) diff --git a/src/adiar/internal/data_structures/level_merger.h b/src/adiar/internal/data_structures/level_merger.h index edcdd515b..d9c51b496 100644 --- a/src/adiar/internal/data_structures/level_merger.h +++ b/src/adiar/internal/data_structures/level_merger.h @@ -30,13 +30,13 @@ namespace adiar::internal { static_assert(0 < FileCount, "At least one file should be merged"); - using stream_t = typename level_stream_t::template stream_t; + using stream_type = typename level_stream_t::template stream_t; public: static size_t memory_usage() { - return FileCount * stream_t::memory_usage(); + return FileCount * stream_type::memory_usage(); } using level_type = ptr_uint64::label_type; @@ -44,7 +44,7 @@ namespace adiar::internal private: Comp _comparator = Comp(); - unique_ptr _level_streams[FileCount]; + unique_ptr _level_streams[FileCount]; public: //////////////////////////////////////////////////////////////////////////////////////////////// @@ -54,7 +54,7 @@ namespace adiar::internal hook(const File (&fs)[FileCount]) { for (size_t idx = 0u; idx < FileCount; idx++) { - _level_streams[idx] = adiar::make_unique(fs[idx]); + _level_streams[idx] = adiar::make_unique(fs[idx]); } } @@ -65,7 +65,7 @@ namespace adiar::internal hook(const dd (&dds)[FileCount]) { for (size_t idx = 0u; idx < FileCount; idx++) { - _level_streams[idx] = adiar::make_unique(dds[idx].file_ptr()); + _level_streams[idx] = adiar::make_unique(dds[idx].file_ptr()); } } @@ -76,7 +76,7 @@ namespace adiar::internal hook(const __dd (&dds)[FileCount]) { for (size_t idx = 0u; idx < FileCount; idx++) { - _level_streams[idx] = adiar::make_unique(dds[idx]); + _level_streams[idx] = adiar::make_unique(dds[idx]); } } @@ -128,7 +128,7 @@ namespace adiar::internal level_type min_level = peek(); // pull from all with min_level - for (const unique_ptr& level_info_stream : _level_streams) { + for (const unique_ptr& level_info_stream : _level_streams) { if (level_info_stream->can_pull() && level_of(level_info_stream->peek()) == min_level) { level_info_stream->pull(); } diff --git a/test/adiar/internal/data_structures/test_level_merger.cpp b/test/adiar/internal/data_structures/test_level_merger.cpp index 1e68f898c..7eba23b4e 100644 --- a/test/adiar/internal/data_structures/test_level_merger.cpp +++ b/test/adiar/internal/data_structures/test_level_merger.cpp @@ -4,8 +4,8 @@ go_bandit([]() { describe("adiar/internal/level_merger.h", []() { - describe("level_merger, ...>", [&]() { - it("can pull from one level_info stream", [&]() { + describe("level_merger, ...>", []() { + it("can pull from one level_info stream", []() { shared_levelized_file f; { // Garbage collect the writer levelized_file_writer fw(f); @@ -35,7 +35,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can peek from one level_info streams", [&]() { + it("can peek from one level_info streams", []() { shared_levelized_file f; { // Garbage collect the writer @@ -62,7 +62,7 @@ go_bandit([]() { AssertThat(merger.pull(), Is().EqualTo(4u)); }); - it("can pull from merge of two level_info streams, where one is empty [1]", [&]() { + it("can pull from merge of two level_info streams, where one is empty [1]", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -82,7 +82,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can pull from merge of two level_info streams, where one is empty [2]", [&]() { + it("can pull from merge of two level_info streams, where one is empty [2]", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -106,7 +106,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can pull from merge of two level_info streams [1]", [&]() { + it("can pull from merge of two level_info streams [1]", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -142,7 +142,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can pull from merge of two level_info streams [2] (std::less)", [&]() { + it("can pull from merge of two level_info streams [2] (std::less)", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -169,7 +169,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can pull from merge of two level_info streams [2] (std::greater)", [&]() { + it("can pull from merge of two level_info streams [2] (std::greater)", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -196,7 +196,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can peek merge of two level_info stream", [&]() { + it("can peek merge of two level_info stream", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -227,7 +227,7 @@ go_bandit([]() { AssertThat(merger.pull(), Is().EqualTo(4u)); }); - it("can merge levels in reverse", [&]() { + it("can merge levels in reverse", []() { shared_levelized_file f1; shared_levelized_file f2; @@ -258,7 +258,7 @@ go_bandit([]() { AssertThat(merger.pull(), Is().EqualTo(1u)); }); - it("can pull, even after the original files have been deleted", [&]() { + it("can pull, even after the original files have been deleted", []() { shared_levelized_file f1 = shared_levelized_file(); shared_levelized_file f2 = shared_levelized_file(); @@ -289,8 +289,8 @@ go_bandit([]() { }); }); - describe("level_merger, ...>", [&]() { - it("can use a single label_file", [&]() { + describe("level_merger, ...>", []() { + it("can use a single label_file", []() { shared_file f; { // Garbage collect the writers @@ -314,7 +314,7 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); - it("can merge two label_files", [&]() { + it("can merge two label_files", []() { shared_file f1; shared_file f2; @@ -345,5 +345,179 @@ go_bandit([]() { AssertThat(merger.can_pull(), Is().False()); }); }); + + describe("level_merger", []() { + const ptr_uint64 terminal_F = ptr_uint64(false); + const ptr_uint64 terminal_T = ptr_uint64(true); + + shared_levelized_file nf_x0; + /* + // 1 ---- x0 + // / \ + // F T + */ + { + node_writer nw(nf_x0); + nw << node(0, node::max_id, terminal_F, terminal_T); + } + + shared_levelized_file nf_x1; + /* + // 1 ---- x1 + // / \ + // F T + */ + { + node_writer nw(nf_x1); + nw << node(1, node::max_id, terminal_F, terminal_T); + } + + + shared_levelized_file nf_x0_or_x2; + /* + // 1 ---- x0 + // / \ + // | T + // | + // 2 ---- x2 + // / \ + // F T + */ + { + node_writer nw(nf_x0_or_x2); + nw << node(2, node::max_id, terminal_F, terminal_T) + << node(0, node::max_id, node::pointer_type(2, node::max_id), terminal_T); + } + + it("can pull from a single diagram [x0]", [&]() { + level_merger, std::less<>, 1> merger; + merger.hook({ dd(nf_x0) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can pull from a single diagram [x1]", [&]() { + level_merger, std::less<>, 1> merger; + merger.hook({ dd(nf_x1) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(1u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can pull from a single diagram [x0 | x2]", [&]() { + level_merger, std::less<>, 1> merger; + merger.hook({ dd(nf_x0_or_x2) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(2u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x0, x1] (std::less)", [&]() { + level_merger, std::less<>, 2> merger; + merger.hook({ dd(nf_x0), dd(nf_x1) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(1u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x1, x0] (std::less)", [&]() { + level_merger, std::less<>, 2> merger; + merger.hook({ dd(nf_x1), dd(nf_x0) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(1u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x1, x0] (std::greater)", [&]() { + level_merger, std::greater<>, 2> merger; + merger.hook({ dd(nf_x1), dd(nf_x0) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(1u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x0, x0 | x2] (std::less)", [&]() { + level_merger, std::less<>, 2> merger; + merger.hook({ dd(nf_x0), dd(nf_x0_or_x2) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(2u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x0 | x2, x0] (std::less)", [&]() { + level_merger, std::less<>, 2> merger; + merger.hook({ dd(nf_x0_or_x2), dd(nf_x0) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(2u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x0 | x2, x1] (std::less)", [&]() { + level_merger, std::less<>, 2> merger; + merger.hook({ dd(nf_x0_or_x2), dd(nf_x1) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(1u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(2u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + + it("can merge levels of two diagrams [x1, x0 | x2] (std::less)", [&]() { + level_merger, std::less<>, 2> merger; + merger.hook({ dd(nf_x1), dd(nf_x0_or_x2) }); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(0u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(1u)); + + AssertThat(merger.can_pull(), Is().True()); + AssertThat(merger.pull(), Is().EqualTo(2u)); + + AssertThat(merger.can_pull(), Is().False()); + }); + }); }); }); From c85d24a8dfb6a86c2f12a03d53f433a8020ee5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 14:24:18 +0200 Subject: [PATCH 17/30] Clean up interface of 'comparison_check' This 'dd' independent interface has bothered me for years... --- src/adiar/internal/algorithms/pred.cpp | 73 ++++++--------- src/adiar/internal/algorithms/pred.h | 125 ++++++++++--------------- src/adiar/zdd/pred.cpp | 19 ++-- 3 files changed, 87 insertions(+), 130 deletions(-) diff --git a/src/adiar/internal/algorithms/pred.cpp b/src/adiar/internal/algorithms/pred.cpp index d519ba69e..9d0c69f28 100644 --- a/src/adiar/internal/algorithms/pred.cpp +++ b/src/adiar/internal/algorithms/pred.cpp @@ -27,17 +27,15 @@ namespace adiar::internal public: static size_t - pq1_upper_bound(const shared_levelized_file& in_1, - const shared_levelized_file& in_2) + pq1_upper_bound(const dd& a, const dd& b) { - return std::max(in_1->max_2level_cut[cut::Internal], in_2->max_2level_cut[cut::Internal]); + return std::max(a->max_2level_cut[cut::Internal], b->max_2level_cut[cut::Internal]); } static size_t - pq2_upper_bound(const shared_levelized_file& in_1, - const shared_levelized_file& in_2) + pq2_upper_bound(const dd& a, const dd& b) { - return std::max(in_1->max_1level_cut[cut::Internal], in_2->max_1level_cut[cut::Internal]); + return std::max(a->max_1level_cut[cut::Internal], b->max_1level_cut[cut::Internal]); } static constexpr size_t @@ -47,9 +45,8 @@ namespace adiar::internal } public: - input_bound_levels(const shared_levelized_file& f0, - const shared_levelized_file& /*f1*/) - : in_meta_1(f0) + input_bound_levels(const dd& a, const dd& /*b*/) + : in_meta_1(a) {} void @@ -173,15 +170,14 @@ namespace adiar::internal /// (breaks canonicity) ////////////////////////////////////////////////////////////////////////////////////////////////// bool - fast_isomorphism_check(const shared_levelized_file& f0, - const shared_levelized_file& f1) + fast_isomorphism_check(const dd& a, const dd& b) { - node_stream<> in_nodes_1(f0); - node_stream<> in_nodes_2(f1); + node_stream<> in_nodes_a(a); + node_stream<> in_nodes_b(b); - while (in_nodes_1.can_pull()) { - adiar_assert(in_nodes_2.can_pull(), "The number of nodes should coincide"); - if (in_nodes_1.pull() != in_nodes_2.pull()) { + while (in_nodes_a.can_pull()) { + adiar_assert(in_nodes_b.can_pull(), "The number of nodes should coincide"); + if (in_nodes_a.pull() != in_nodes_b.pull()) { #ifdef ADIAR_STATS stats_equality.fast_check.exit_on_mismatch += 1u; #endif @@ -193,22 +189,21 @@ namespace adiar::internal ////////////////////////////////////////////////////////////////////////////////////////////////// bool - is_isomorphic(const exec_policy& ep, - const shared_levelized_file& f0, - const shared_levelized_file& f1, - const bool negate0, - const bool negate1) + is_isomorphic(const exec_policy& ep, const dd& a, const dd& b) { + const bool a_negated = a.is_negated(); + const bool b_negated = b.is_negated(); + // Are they literally referring to the same underlying file? - if (f0 == f1) { + if (a.file_ptr() == b.file_ptr()) { #ifdef ADIAR_STATS stats_equality.exit_on_same_file += 1u; #endif - return negate0 == negate1; + return a_negated == b_negated; } // Are they trivially not the same, since they have different number of nodes? - if (f0->size() != f1->size()) { + if (a->size() != b->size()) { #ifdef ADIAR_STATS stats_equality.exit_on_nodecount += 1u; #endif @@ -216,7 +211,7 @@ namespace adiar::internal } // Are they trivially not the same, since their width is different? - if (f0->width != f1->width) { + if (a->width != b->width) { #ifdef ADIAR_STATS stats_equality.exit_on_width += 1u; #endif @@ -224,8 +219,8 @@ namespace adiar::internal } // Are they trivially not the same, since they have different number of terminal arcs? - if (f0->number_of_terminals[negate0] != f1->number_of_terminals[negate1] - || f0->number_of_terminals[!negate0] != f1->number_of_terminals[!negate1]) { + if (a->number_of_terminals[a_negated] != b->number_of_terminals[b_negated] + || a->number_of_terminals[!a_negated] != b->number_of_terminals[!b_negated]) { #ifdef ADIAR_STATS stats_equality.exit_on_terminalcount += 1u; #endif @@ -233,7 +228,7 @@ namespace adiar::internal } // Are they trivially not the same, since they have different number of levels? - if (f0->levels() != f1->levels()) { + if (a->levels() != b->levels()) { #ifdef ADIAR_STATS stats_equality.exit_on_varcount += 1u; #endif @@ -242,12 +237,12 @@ namespace adiar::internal // Are they trivially not the same, since the labels or the size of each level does not match? { // Create new scope to garbage collect the two meta_streams early - level_info_stream<> in_meta_0(f0); - level_info_stream<> in_meta_1(f1); + level_info_stream<> in_meta_a(a); + level_info_stream<> in_meta_b(b); - while (in_meta_0.can_pull()) { - adiar_assert(in_meta_1.can_pull(), "level_info files are same size"); - if (in_meta_0.pull() != in_meta_1.pull()) { + while (in_meta_a.can_pull()) { + adiar_assert(in_meta_b.can_pull(), "level_info files are same size"); + if (in_meta_a.pull() != in_meta_b.pull()) { #ifdef ADIAR_STATS stats_equality.exit_on_levels_mismatch += 1u; #endif @@ -260,22 +255,16 @@ namespace adiar::internal // can just ignore the id (and only focus on the label and terminal values). // Compare their content to discern whether there exists an isomorphism between them. - if (f0->is_canonical() && f1->is_canonical() && negate0 == negate1) { + if (a->is_canonical() && b->is_canonical() && a_negated == b_negated) { #ifdef ADIAR_STATS stats_equality.fast_check.runs += 1u; #endif - return fast_isomorphism_check(f0, f1); + return fast_isomorphism_check(a, b); } else { #ifdef ADIAR_STATS stats_equality.slow_check.runs += 1u; #endif - return comparison_check(ep, f0, f1, negate0, negate1); + return comparison_check(ep, a, b); } } - - bool - is_isomorphic(const exec_policy& ep, const dd& a, const dd& b) - { - return is_isomorphic(ep, a.file_ptr(), b.file_ptr(), a.is_negated(), b.is_negated()); - } } diff --git a/src/adiar/internal/algorithms/pred.h b/src/adiar/internal/algorithms/pred.h index c6bd61c6c..b482642c3 100644 --- a/src/adiar/internal/algorithms/pred.h +++ b/src/adiar/internal/algorithms/pred.h @@ -19,26 +19,6 @@ namespace adiar::internal /// Struct to hold statistics for equality checking extern statistics::equality_t stats_equality; - ////////////////////////////////////////////////////////////////////////////////////////////////// - /// \brief Compute whether two shared levelized node files (with associated - /// negation flags) are isomorphic. - /// - /// \details Checks whether the two files are isomorphic, i.e. whether there is a - /// structure-preserving mapping between `f0` and `f1`. This assumes, that both files are - /// of a unique reduced form. - /// - /// \param fi The two files of nodes to compare. - /// \param negatei Whether the nodes of fi should be read in negated form - /// - /// \return Whether `f0` and `f1` have isomorphic DAGs when applying the given negation flags. - ////////////////////////////////////////////////////////////////////////////////////////////////// - bool - is_isomorphic(const exec_policy& ep, - const shared_levelized_file& f0, - const shared_levelized_file& f1, - const bool negate0 = false, - const bool negate1 = false); - ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Computes whether two decision diagrams are isomorphic; i.e. whether they are equivalent /// (under the same deletion-rule). @@ -75,19 +55,17 @@ namespace adiar::internal using comparison_priority_queue_2_t = priority_queue, request_second_lt>>; - template + template bool - __comparison_check(const shared_levelized_file& f0, - const shared_levelized_file& f1, - const bool negate0, - const bool negate1, + __comparison_check(const typename Policy::dd_type& in_0, + const typename Policy::dd_type& in_1, const tpie::memory_size_type pq_1_memory, const tpie::memory_size_type pq_2_memory, const size_t max_pq_size) { // Set up input - node_stream<> in_nodes_0(f0, negate0); - node_stream<> in_nodes_1(f1, negate1); + node_stream<> in_nodes_0(in_0); + node_stream<> in_nodes_1(in_1); node v0 = in_nodes_0.pull(); node v1 = in_nodes_1.pull(); @@ -95,23 +73,23 @@ namespace adiar::internal // Edge-case for terminals if (v0.is_terminal() || v1.is_terminal()) { bool ret_value; - if (comp_policy::resolve_terminals(v0, v1, ret_value)) { return ret_value; } + if (Policy::resolve_terminals(v0, v1, ret_value)) { return ret_value; } } if (v0.low().is_terminal() && v0.high().is_terminal() && v1.low().is_terminal() && v1.high().is_terminal()) { - return comp_policy::resolve_singletons(v0, v1); + return Policy::resolve_singletons(v0, v1); } // Set up cross-level priority queue - pq_1_t comparison_pq_1({ f0, f1 }, pq_1_memory, max_pq_size, stats_equality.lpq); + PriorityQueue_1 comparison_pq_1({ in_0, in_1 }, pq_1_memory, max_pq_size, stats_equality.lpq); comparison_pq_1.push({ { v0.uid(), v1.uid() }, {} }); // Set up per-level priority queue - pq_2_t comparison_pq_2(pq_2_memory, max_pq_size); + PriorityQueue_2 comparison_pq_2(pq_2_memory, max_pq_size); // Initialise level checking - typename comp_policy::level_check_t level_checker(f0, f1); + typename Policy::level_check_t level_checker(in_0, in_1); while (!comparison_pq_1.empty()) { // Set up next level @@ -135,7 +113,7 @@ namespace adiar::internal } // Seek request partially in stream - const typename comp_policy::pointer_type t_seek = + const typename Policy::pointer_type t_seek = req.empty_carry() ? req.target.first() : req.target.second(); while (v0.uid() < t_seek && in_nodes_0.can_pull()) { v0 = in_nodes_0.pull(); } @@ -150,7 +128,7 @@ namespace adiar::internal if (req.empty_carry() && req.target[0].is_node() && req.target[1].is_node() && req.target[0].label() == req.target[1].label() && (v0.uid() != req.target[0] || v1.uid() != req.target[1])) { - const typename comp_policy::children_type children = + const typename Policy::children_type children = (req.target[0] == v0.uid() ? v0 : v1).children(); comparison_pq_2.push({ req.target, { children } }); @@ -161,29 +139,29 @@ namespace adiar::internal if (level_checker.on_step()) { return level_checker.termination_value; } // Obtain children or root for both nodes (depending on level) - const tuple children = - comp_policy::merge(req, t_seek, v0, v1); + const tuple children = + Policy::merge(req, t_seek, v0, v1); // Create pairing of product children and obtain new recursion targets - const tuple rec_pair_0 = { children[0][false], - children[1][false] }; + const tuple rec_pair_0 = { children[0][false], + children[1][false] }; - const tuple rec_pair_1 = { children[0][true], - children[1][true] }; + const tuple rec_pair_1 = { children[0][true], + children[1][true] }; // Forward pairing and return early if possible - if (comp_policy::resolve_request(comparison_pq_1, rec_pair_0) - || comp_policy::resolve_request(comparison_pq_1, rec_pair_1)) { - return comp_policy::early_return_value; + if (Policy::resolve_request(comparison_pq_1, rec_pair_0) + || Policy::resolve_request(comparison_pq_1, rec_pair_1)) { + return Policy::early_return_value; } } } - return comp_policy::no_early_return_value; + return Policy::no_early_return_value; } ////////////////////////////////////////////////////////////////////////////////////////////////// - /// Behaviour can be changed with the 'comp_policy'. + /// Behaviour can be changed with the 'Policy'. /// /// - The 'resolve_terminals' function resolves the case of being given two terminals. /// @@ -196,17 +174,15 @@ namespace adiar::internal /// - The constexpr 'early_return_value' and 'no_early_return_value' change the return value on /// early returns. /// - /// This 'comp_policy' also should inherit (or provide) the general policy for the + /// This 'Policy' also should inherit (or provide) the general policy for the /// decision_diagram used (i.e. bdd_policy in bdd/bdd.h, zdd_policy in zdd/zdd.h and so on). This /// provides the following functions ////////////////////////////////////////////////////////////////////////////////////////////////// - template + template bool comparison_check(const exec_policy& ep, - const shared_levelized_file& f0, - const shared_levelized_file& f1, - const bool negate0, - const bool negate1) + const typename Policy::dd_type& in_0, + const typename Policy::dd_type& in_1) { // Compute amount of memory available for auxiliary data structures after having opened all // streams. @@ -217,7 +193,7 @@ namespace adiar::internal // Input - 2 * node_stream<>::memory_usage() // Level checker policy - - comp_policy::level_check_t::memory_usage(); + - Policy::level_check_t::memory_usage(); constexpr size_t data_structures_in_pq_1 = comparison_priority_queue_1_t::data_structures; @@ -243,57 +219,52 @@ namespace adiar::internal const bool external_only = ep.template get() == exec_policy::memory::External; - const size_t pq_1_bound = comp_policy::level_check_t::pq1_upper_bound(f0, f1); + const size_t pq_1_bound = Policy::level_check_t::pq1_upper_bound(in_0, in_1); const size_t max_pq_1_size = internal_only ? std::min(pq_1_memory_fits, pq_1_bound) : pq_1_bound; - const size_t pq_2_bound = comp_policy::level_check_t::pq2_upper_bound(f0, f1); + const size_t pq_2_bound = Policy::level_check_t::pq2_upper_bound(in_0, in_1); const size_t max_pq_2_size = internal_only ? std::min(pq_2_memory_fits, pq_2_bound) : pq_2_bound; // TODO: Only one element per node in pq_2, so maximum is width (or their product)! - if (!external_only && max_pq_1_size <= no_lookahead_bound(comp_policy::lookahead_bound())) { + if (!external_only && max_pq_1_size <= no_lookahead_bound(Policy::lookahead_bound())) { #ifdef ADIAR_STATS stats_equality.lpq.unbucketed += 1u; #endif - return __comparison_check, - comparison_priority_queue_2_t>( - f0, f1, negate0, negate1, pq_1_internal_memory, pq_2_internal_memory, max_pq_1_size); + using priority_queue_1_type = comparison_priority_queue_1_t<0, memory_mode::Internal>; + using priority_queue_2_type = comparison_priority_queue_2_t; + + return __comparison_check( + in_0, in_1, pq_1_internal_memory, pq_2_internal_memory, max_pq_1_size); } else if (!external_only && max_pq_1_size <= pq_1_memory_fits && max_pq_2_size <= pq_2_memory_fits) { #ifdef ADIAR_STATS stats_equality.lpq.internal += 1u; #endif - return __comparison_check< - comp_policy, - comparison_priority_queue_1_t, - comparison_priority_queue_2_t>( - f0, f1, negate0, negate1, pq_1_internal_memory, pq_2_internal_memory, max_pq_1_size); + using priority_queue_1_type = + comparison_priority_queue_1_t; + using priority_queue_2_type = comparison_priority_queue_2_t; + + return __comparison_check( + in_0, in_1, pq_1_internal_memory, pq_2_internal_memory, max_pq_1_size); } else { #ifdef ADIAR_STATS stats_equality.lpq.external += 1u; #endif + using priority_queue_1_type = + comparison_priority_queue_1_t; + using priority_queue_2_type = comparison_priority_queue_2_t; + const size_t pq_1_memory = aux_available_memory / 2; const size_t pq_2_memory = pq_1_memory; - return __comparison_check< - comp_policy, - comparison_priority_queue_1_t, - comparison_priority_queue_2_t>( - f0, f1, negate0, negate1, pq_1_memory, pq_2_memory, max_pq_1_size); + return __comparison_check( + in_0, in_1, pq_1_memory, pq_2_memory, max_pq_1_size); } } - - template - bool - comparison_check(const exec_policy& ep, const dd& a, const dd& b) - { - return comparison_check( - ep, a.file_ptr(), b.file_ptr(), a.is_negated(), b.is_negated()); - } } #endif // ADIAR_INTERNAL_ALGORITHMS_PRED_H diff --git a/src/adiar/zdd/pred.cpp b/src/adiar/zdd/pred.cpp index 03dcf2d95..db7dda5e0 100644 --- a/src/adiar/zdd/pred.cpp +++ b/src/adiar/zdd/pred.cpp @@ -79,26 +79,24 @@ namespace adiar } ////////////////////////////////////////////////////////////////////////////////////////////////// - template + template class ignore_levels { public: static size_t - pq1_upper_bound(const internal::shared_levelized_file& in_1, - const internal::shared_levelized_file& in_2) + pq1_upper_bound(const zdd& A, const zdd& B) { - const internal::safe_size_t max_2level_cut_1 = in_1->max_2level_cut[ct_1]; - const internal::safe_size_t max_2level_cut_2 = in_2->max_2level_cut[ct_2]; + const internal::safe_size_t max_2level_cut_1 = A->max_2level_cut[ct_A]; + const internal::safe_size_t max_2level_cut_2 = B->max_2level_cut[ct_B]; return internal::to_size(max_2level_cut_1 * max_2level_cut_2); } static size_t - pq2_upper_bound(const internal::shared_levelized_file& in_1, - const internal::shared_levelized_file& in_2) + pq2_upper_bound(const zdd& A, const zdd& B) { - const internal::safe_size_t max_1level_cut_1 = in_1->max_1level_cut[ct_1]; - const internal::safe_size_t max_1level_cut_2 = in_2->max_1level_cut[ct_2]; + const internal::safe_size_t max_1level_cut_1 = A->max_1level_cut[ct_A]; + const internal::safe_size_t max_1level_cut_2 = B->max_1level_cut[ct_B]; return internal::to_size(max_1level_cut_1 * max_1level_cut_2); } @@ -110,8 +108,7 @@ namespace adiar } public: - ignore_levels(const internal::shared_levelized_file& /*f1*/, - const internal::shared_levelized_file& /*f2*/) + ignore_levels(const zdd& /*A*/, const zdd& /*B*/) { /* do nothing */ } From 6493fa50bf7f2138e2fa616cdda36d0a5d608b4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Tue, 18 Jun 2024 15:02:19 +0200 Subject: [PATCH 18/30] Clean up tests for 'bdd_apply' --- test/adiar/bdd/test_apply.cpp | 411 +++++++++++++++++++++++++++++----- 1 file changed, 354 insertions(+), 57 deletions(-) diff --git a/test/adiar/bdd/test_apply.cpp b/test/adiar/bdd/test_apply.cpp index 8e84c2b3f..d4a29370a 100644 --- a/test/adiar/bdd/test_apply.cpp +++ b/test/adiar/bdd/test_apply.cpp @@ -342,7 +342,7 @@ go_bandit([]() { // complicated algorithm describe("bdd_and(f,g)", [&]() { - it("should resolve F /\\ T terminal-only BDDs", [&]() { + it("resolves F /\\ T terminal-only BDDs", [&]() { __bdd out = bdd_and(bdd_F, bdd_T); node_test_stream out_nodes(out); @@ -368,7 +368,7 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should resolve T /\\ T terminal-only BDDs", [&]() { + it("resolves T /\\ T terminal-only BDDs", [&]() { shared_levelized_file bdd_T2; { node_writer w(bdd_T2); @@ -400,14 +400,14 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should shortcut on irrelevance on x0 /\\ T", [&]() { + it("shortcuts on irrelevance on x0 /\\ T", [&]() { __bdd out = bdd_and(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().False()); }); - it("should shortcut F /\\ x0", [&]() { + it("shortcuts F /\\ x0", [&]() { __bdd out = bdd_and(bdd_F, bdd_x0); node_test_stream out_nodes(out); @@ -434,7 +434,7 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should shortcut F /\\ [2]", [&]() { + it("shortcuts F /\\ [2]", [&]() { __bdd out = bdd_and(bdd_F, bdd_2); node_test_stream out_nodes(out); @@ -461,30 +461,118 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should return input on being given the same BDD twice", [&]() { + it("returns input on being given the same BDD twice", [&]() { __bdd out = bdd_and(bdd_1, bdd_1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); AssertThat(out._negate, Is().False()); }); + + it("collapses on the same BDD twice, where one is negated [left]", [&]() { + __bdd out = bdd_and(bdd_not(bdd_1), bdd_1); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(false))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(0u)); + }); + + it("collapses on the same BDD twice, where one is negated [right]", [&]() { + __bdd out = bdd_and(bdd_1, bdd_not(bdd_1)); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(false))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(0u)); + }); }); describe("bdd_nand(f,g)", [&]() { - it("should shortcut on negating on T and x0", [&]() { + it("shortcuts on negating on T and x0", [&]() { __bdd out = bdd_nand(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().True()); }); - it("should shortcut on negating on x0 and T", [&]() { + it("shortcuts on negating on x0 and T", [&]() { __bdd out = bdd_nand(bdd_T, bdd_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().True()); }); - it("should collapse on the same BDD twice, where one is negated", [&]() { + it("returns input on being given the same BDD twice", [&]() { + __bdd out = bdd_nand(bdd_1, bdd_1); + + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); + AssertThat(out._negate, Is().True()); + }); + + it("collapses on the same BDD twice, where one is negated [left]", [&]() { + __bdd out = bdd_nand(bdd_not(bdd_2), bdd_2); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); + + it("collapses on the same BDD twice, where one is negated [right]", [&]() { __bdd out = bdd_nand(bdd_2, bdd_not(bdd_2)); node_test_stream out_nodes(out); @@ -513,7 +601,7 @@ go_bandit([]() { }); describe("bdd_or(f,g)", [&]() { - it("should resolve T \\/ F terminal-only BDDs", [&]() { + it("resolves T \\/ F terminal-only BDDs", [&]() { __bdd out = bdd_or(bdd_T, bdd_F); node_test_stream out_nodes(out); @@ -539,7 +627,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should resolve F \\/ F terminal-only BDDs", [&]() { + it("resolves F \\/ F terminal-only BDDs", [&]() { shared_levelized_file bdd_F2; { @@ -572,21 +660,21 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should shortcut on irrelevance on x0 \\/ F", [&]() { + it("shortcuts on irrelevance on x0 \\/ F", [&]() { __bdd out = bdd_or(bdd_x0, bdd_F); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().False()); }); - it("should OR shortcut on irrelevance F \\/ x0", [&]() { + it("shortcuts on irrelevance F \\/ x0", [&]() { __bdd out = bdd_or(bdd_F, bdd_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().False()); }); - it("should shortcut [1] \\/ T", [&]() { + it("shortcuts [1] \\/ T", [&]() { __bdd out = bdd_or(bdd_1, bdd_T); node_test_stream out_nodes(out); @@ -613,7 +701,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should compute (and shortcut) [2] \\/ T", [&]() { + it("shortcuts [2] \\/ T", [&]() { __bdd out = bdd_or(bdd_2, bdd_T); node_test_stream out_nodes(out); @@ -639,10 +727,85 @@ go_bandit([]() { AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], Is().EqualTo(1u)); }); + + it("returns input on being given the same BDD twice", [&]() { + __bdd out = bdd_or(bdd_1, bdd_1); + + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); + AssertThat(out._negate, Is().False()); + }); + + it("collapses on the same BDD twice, where one is negated [left]", [&]() { + __bdd out = bdd_or(bdd_not(bdd_1), bdd_1); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); + + it("collapses on the same BDD twice, where one is negated [right]", [&]() { + __bdd out = bdd_or(bdd_1, bdd_not(bdd_1)); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); + + it("returns input on being given the same BDD twice, when both are negated", [&]() { + __bdd out = bdd_or(bdd_not(bdd_1), bdd_not(bdd_1)); + + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); + AssertThat(out._negate, Is().True()); + }); }); describe("bdd_nor(f,g)", [&]() { - it("should collapse on the same BDD twice to a terminal, where one is negated [2]", [&]() { + it("returns input on being given the same BDD twice", [&]() { + __bdd out = bdd_nor(bdd_1, bdd_1); + + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_1)); + AssertThat(out._negate, Is().True()); + }); + + it("collapses on the same BDD twice, where one is negated [left]", [&]() { __bdd out = bdd_nor(bdd_not(bdd_3), bdd_3); node_test_stream out_nodes(out); @@ -668,10 +831,37 @@ go_bandit([]() { AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], Is().EqualTo(0u)); }); + + it("collapses on the same BDD twice, where one is negated [right]", [&]() { + __bdd out = bdd_nor(bdd_3, bdd_not(bdd_3)); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(false))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(0u)); + }); }); describe("bdd_xor(f,g)", [&]() { - it("should resolve F ^ T terminal-only BDDs", [&]() { + it("resolves F ^ T terminal-only BDDs", [&]() { __bdd out = bdd_xor(bdd_F, bdd_T); node_test_stream out_nodes(out); @@ -697,7 +887,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should resolve T ^ T terminal-only BDDs", [&]() { + it("resolves T ^ T terminal-only BDDs", [&]() { __bdd out = bdd_xor(bdd_T, bdd_T); node_test_stream out_nodes(out); @@ -723,21 +913,21 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should shortcut on negating on x0 ^ T", [&]() { + it("shortcuts on negating on x0 ^ T", [&]() { __bdd out = bdd_xor(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().True()); }); - it("should shortcut on negating on T ^ x0", [&]() { + it("shortcuts on negating on T ^ x0", [&]() { __bdd out = bdd_xor(bdd_x0, bdd_T); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().True()); }); - it("should collapse on the same BDD twice", [&]() { + it("collapses on the same BDD twice", [&]() { __bdd out = bdd_xor(bdd_1, bdd_1); node_test_stream out_nodes(out); @@ -764,7 +954,61 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should collapse on the same BDD twice to a terminal, when both are negated", [&]() { + it("collapses on the same BDD twice, where one is negated [left]", [&]() { + __bdd out = bdd_xor(bdd_not(bdd_1), bdd_1); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); + + it("collapses on the same BDD twice, where one is negated [right]", [&]() { + __bdd out = bdd_xor(bdd_2, bdd_not(bdd_2)); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); + + it("collapses on the same BDD twice, when both are negated", [&]() { __bdd out = bdd_xor(bdd_not(bdd_1), bdd_not(bdd_1)); node_test_stream out_nodes(out); @@ -793,7 +1037,7 @@ go_bandit([]() { }); describe("bdd_imp(f,g)", [&]() { - it("should resolve F -> T terminal-only BDDs", [&]() { + it("resolves F -> T terminal-only BDDs", [&]() { __bdd out = bdd_imp(bdd_F, bdd_T); node_test_stream out_nodes(out); @@ -819,7 +1063,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should resolve T -> F terminal-only BDDs", [&]() { + it("resolves T -> F terminal-only BDDs", [&]() { __bdd out = bdd_imp(bdd_T, bdd_F); node_test_stream out_nodes(out); @@ -845,7 +1089,7 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should resolve T -> T terminal-only BDDs", [&]() { + it("resolves T -> T terminal-only BDDs", [&]() { __bdd out = bdd_imp(bdd_T, bdd_T); node_test_stream out_nodes(out); @@ -871,14 +1115,14 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should shortcut on irrelevance on T -> x0", [&]() { + it("shortcuts on irrelevance on T -> x0", [&]() { __bdd out = bdd_imp(bdd_T, bdd_x0); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().False()); }); - it("should shortcut F -> [1]", [&]() { + it("shortcuts F -> [1]", [&]() { __bdd out = bdd_imp(bdd_F, bdd_1); node_test_stream out_nodes(out); @@ -905,21 +1149,74 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should return the input when given the same BDD twice, where one is negated [1]", - [&]() { - __bdd out = bdd_imp(bdd_not(bdd_2), bdd_2); + it("collapses when given the same BDD twice", [&]() { + __bdd out = bdd_imp(bdd_1, bdd_1); - AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_2)); - AssertThat(out._negate, - Is().False()); // negated the already negated input doubly-negating - }); + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); + + it("returns input when given the same BDD twice, where one is negated [left]", [&]() { + __bdd out = bdd_imp(bdd_not(bdd_2), bdd_2); + + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_2)); + AssertThat(out._negate, + Is().False()); // negated the already negated input doubly-negating + }); - it("should return input when given the same BDD twice, where one is negated [2]", [&]() { + it("returns input when given the same BDD twice, where one is negated [right]", [&]() { __bdd out = bdd_imp(bdd_2, bdd_not(bdd_2)); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_2)); AssertThat(out._negate, Is().True()); // negated the first of the two }); + + it("collapses when given the same BDD twice, when both are negated", [&]() { + __bdd out = bdd_imp(bdd_not(bdd_1), bdd_not(bdd_1)); + + node_test_stream out_nodes(out); + + AssertThat(out_nodes.can_pull(), Is().True()); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + + AssertThat(out_nodes.can_pull(), Is().False()); + + AssertThat(out.get<__bdd::shared_node_file_type>()->levels(), Is().EqualTo(0u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_False], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::Internal_True], + Is().EqualTo(1u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->max_1level_cut[cut::All], + Is().EqualTo(1u)); + + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[false], + Is().EqualTo(0u)); + AssertThat(out.get<__bdd::shared_node_file_type>()->number_of_terminals[true], + Is().EqualTo(1u)); + }); }); }); @@ -953,7 +1250,7 @@ go_bandit([]() { */ describe("bdd_and(f,g)", [&]() { - it("should x0 and !x0", [&]() { + it("computes x0 and !x0", [&]() { /* // 1 ---- x0 // / \ @@ -992,7 +1289,7 @@ go_bandit([]() { Is().EqualTo(0u)); }); - it("should compute (and shortcut) BBD 1 /\\ [2]", [&]() { + it("computes (and shortcut) BBD 1 /\\ [2]", [&]() { /* // 1 ---- x0 // X @@ -1097,7 +1394,7 @@ go_bandit([]() { Is().EqualTo(4u)); }); - it("should group all recursion requests together", [&]() { + it("groups all recursion requests together", [&]() { // This is a counter-example to the prior "break ties on first() with // second()" approach. Here we will have three requests to the level of // x2, but in the following order: @@ -1215,7 +1512,7 @@ go_bandit([]() { describe("bdd_or(f,g)", [&]() { // TODO: this one too? - it("should shortcut on x0 \\/ x2", [&]() { + it("shortcuts on x0 \\/ x2", [&]() { /* // 1 ---- x0 // / \ @@ -1268,7 +1565,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute (and shortcut) [1] \\/ [2]", [&]() { + it("computes (and shortcut) [1] \\/ [2]", [&]() { /* // 1 ---- x0 // / \ @@ -1359,7 +1656,7 @@ go_bandit([]() { }); describe("bdd_xor(f,g)", [&]() { - it("should compute x0 ^ x1", [&]() { + it("computes x0 ^ x1", [&]() { /* The order on the leaves are due to the sorting of terminal requests // after evaluating x0 // @@ -1420,7 +1717,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute [2] ^ x2", [&]() { + it("computes [2] ^ x2", [&]() { /* // ---- x0 // @@ -1501,7 +1798,7 @@ go_bandit([]() { Is().EqualTo(3u)); }); - it("should compute [1] ^ [2]", [&]() { + it("computes [1] ^ [2]", [&]() { /* There is no shortcutting possible on an XOR, so see the product construction above. */ @@ -1607,7 +1904,7 @@ go_bandit([]() { Is().EqualTo(4u)); }); - it("should compute [3] ^ [1]", [&]() { + it("computes [3] ^ [1]", [&]() { /* The queue pq_2 is used to forward data across the level. When // [1] and 3 are combined, this is needed // @@ -1736,7 +2033,7 @@ go_bandit([]() { Is().EqualTo(5u)); }); - it("should compute in different order than random access", [&]() { + it("computes in different order than random access", [&]() { /* // Result of [canon] ^ [indexable] // @@ -1872,7 +2169,7 @@ go_bandit([]() { }); describe("bdd_imp(f,g)", [&]() { - it("should shortcut on x0 -> x1", [&]() { + it("shortcuts on x0 -> x1", [&]() { /* The order on the leaves are due to the sorting of terminal requests // after evaluating x0 // @@ -1953,7 +2250,7 @@ go_bandit([]() { // Non-Canonical: bdd_1, bdd_3 describe("bdd_and(f,g)", [&]() { - it("should compute (and shortcut) [1] /\\ [2]", [&]() { + it("computes (and shortcut) [1] /\\ [2]", [&]() { /* // 1 ---- x0 // X @@ -2060,7 +2357,7 @@ go_bandit([]() { }); describe("bdd_xor(f,g)", [&]() { - it("should compute x0 ^ !x0 (same level)", [&]() { + it("computes x0 ^ !x0 (same level)", [&]() { /* // 1 ---- x0 // / \ @@ -2097,7 +2394,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute x0 ^ x1 (different levels, random access for first level)", [&]() { + it("computes x0 ^ x1 (different levels, random access for first level)", [&]() { /* The order on the leaves are due to the sorting of terminal requests // after evaluating x0 // @@ -2158,7 +2455,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute x1 ^ x0 (different levels, random access for second level)", [&]() { + it("computes x1 ^ x0 (different levels, random access for second level)", [&]() { /* The order on the leaves are due to the sorting of terminal requests // after evaluating x0 // @@ -2327,7 +2624,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should sort requests first by scanning index then by random acces index", [&]() { + it("sorts requests first by scanning index then by random acces index", [&]() { shared_levelized_file bdd_wide2; /* // 1 ---- x0 @@ -2479,7 +2776,7 @@ go_bandit([]() { Is().EqualTo(3u)); }); - it("should random access on the thinnest ([thin] ^ [wide])", [&]() { + it("uses random access on the thinnest ([thin] ^ [wide])", [&]() { /* Result of [thin] ^ [wide] // // (1,1) ---- x0 @@ -2581,7 +2878,7 @@ go_bandit([]() { Is().EqualTo(6u)); }); - it("should random access on the thinnest ([wide] ^ [thin])", [&]() { + it("uses random access on the thinnest ([wide] ^ [thin])", [&]() { /* Result of [wide] ^ [thin] // // (1,1) ---- x0 @@ -2681,7 +2978,7 @@ go_bandit([]() { Is().EqualTo(6u)); }); - it("should random access on non-canonical but indexable ([canonical] ^ [indexable])", + it("uses random access on non-canonical but indexable ([canonical] ^ [indexable])", [&]() { __bdd out = bdd_xor(ep, bdd_canon, bdd_indexable); @@ -2797,7 +3094,7 @@ go_bandit([]() { Is().EqualTo(6u)); }); - it("should random access non-canonical but indexable ([indexable] ^ [canonical])", [&]() { + it("uses random access non-canonical but indexable ([indexable] ^ [canonical])", [&]() { __bdd out = bdd_xor(ep, bdd_indexable, bdd_canon); arc_test_stream arcs(out); @@ -2907,7 +3204,7 @@ go_bandit([]() { Is().EqualTo(6u)); }); - it("should random access on indexable ([canonical] ^ [non-indexable])", [&]() { + it("uses random access on indexable ([canonical] ^ [non-indexable])", [&]() { __bdd out = bdd_xor(ep, bdd_canon, bdd_unindexable); arc_test_stream arcs(out); @@ -3017,7 +3314,7 @@ go_bandit([]() { Is().EqualTo(6u)); }); - it("should random access on indexable ([non-indexable] ^ [canonical])", [&]() { + it("uses random access on indexable ([non-indexable] ^ [canonical])", [&]() { __bdd out = bdd_xor(ep, bdd_unindexable, bdd_canon); arc_test_stream arcs(out); From 075ca23255381748d527828f62b33e0bdd58d8bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Wed, 19 Jun 2024 09:15:34 +0200 Subject: [PATCH 19/30] Clean up of 'bdd_ite' implementation --- src/adiar/bdd/if_then_else.cpp | 272 ++++++++++++++------------- test/adiar/bdd/test_if_then_else.cpp | 72 +++---- 2 files changed, 174 insertions(+), 170 deletions(-) diff --git a/src/adiar/bdd/if_then_else.cpp b/src/adiar/bdd/if_then_else.cpp index ba80a6164..6ef9169d2 100644 --- a/src/adiar/bdd/if_then_else.cpp +++ b/src/adiar/bdd/if_then_else.cpp @@ -146,9 +146,9 @@ namespace adiar } } - template + template inline void - __ite_resolve_request(pq_1_t& ite_pq_1, + __ite_resolve_request(PriorityQueue_1& ite_pq_1, internal::arc_writer& aw, const internal::node::pointer_type source, internal::node::pointer_type r_if, @@ -179,7 +179,7 @@ namespace adiar } } - template + template __bdd __bdd_ite(const exec_policy& ep, const bdd& bdd_if, @@ -192,28 +192,14 @@ namespace adiar const size_t pq_3_memory, const size_t max_pq_3_size) { - // Now, at this point we will not defer to using the Apply, so we can take up memory by opening - // the input streams and evaluating trivial conditionals. internal::node_stream<> in_nodes_if(bdd_if); - internal::node v_if = in_nodes_if.pull(); - - if (v_if.is_terminal()) { return v_if.value() ? bdd_then : bdd_else; } + bdd::node_type v_if = in_nodes_if.pull(); internal::node_stream<> in_nodes_then(bdd_then); - internal::node v_then = in_nodes_then.pull(); + bdd::node_type v_then = in_nodes_then.pull(); internal::node_stream<> in_nodes_else(bdd_else); - internal::node v_else = in_nodes_else.pull(); - - // If the levels of 'then' and 'else' are disjoint and the 'if' BDD is above the two others, - // then we can merely zip the 'then' and 'else' BDDs. This is only O((N1+N2+N3)/B) I/Os! - if (bdd_maxvar(bdd_if) < v_then.label() && bdd_maxvar(bdd_if) < v_else.label() - && internal::disjoint_levels(bdd_then, bdd_else)) { - return __ite_zip_bdds(bdd_if, bdd_then, bdd_else); - } - - // From here on forward, we probably cannot get away from actually having to - // do the 3-ary product construction. + bdd::node_type v_else = in_nodes_else.pull(); // Set up output internal::shared_levelized_file out_arcs; @@ -222,85 +208,82 @@ namespace adiar out_arcs->max_1level_cut = 0; // Set up cross-level priority queue - pq_1_t ite_pq_1({ bdd_if, bdd_then, bdd_else }, pq_1_memory, max_pq_1_size, stats_prod3.lpq); + PriorityQueue_1 pq_1( + { bdd_if, bdd_then, bdd_else }, pq_1_memory, max_pq_1_size, stats_prod3.lpq); + // TODO: Add support for nil parents and replace loop unrolling below with: + // + /* pq_1.push({ { v_if.uid(), v_then.uid(), v_else.uid() }, {}, { ptr_uint64::nil() } }); */ // Set up per-level priority queues - pq_2_t ite_pq_2(pq_2_memory, max_pq_2_size); - pq_3_t ite_pq_3(pq_3_memory, max_pq_3_size); + PriorityQueue_2 pq_2(pq_2_memory, max_pq_2_size); + PriorityQueue_3 pq_3(pq_3_memory, max_pq_3_size); // Process root and create initial recursion requests { - const internal::node::label_type out_label = - first(v_if.uid(), v_then.uid(), v_else.uid()).label(); + const bdd::label_type out_label = first(v_if.uid(), v_then.uid(), v_else.uid()).label(); - internal::node::pointer_type low_if, low_then, low_else, high_if, high_then, high_else; + bdd::pointer_type low_if, low_then, low_else, high_if, high_then, high_else; ite_init_request(in_nodes_if, v_if, out_label, low_if, high_if); ite_init_request(in_nodes_then, v_then, out_label, low_then, high_then); ite_init_request(in_nodes_else, v_else, out_label, low_else, high_else); - const internal::node::uid_type out_uid(out_label, 0); - __ite_resolve_request(ite_pq_1, aw, out_uid.as_ptr(false), low_if, low_then, low_else); - __ite_resolve_request(ite_pq_1, aw, out_uid.as_ptr(true), high_if, high_then, high_else); + const bdd::node_type::uid_type out_uid(out_label, 0); + __ite_resolve_request(pq_1, aw, out_uid.as_ptr(false), low_if, low_then, low_else); + __ite_resolve_request(pq_1, aw, out_uid.as_ptr(true), high_if, high_then, high_else); aw.push(internal::level_info(out_label, 1)); } // Process all nodes in topological order of both BDDs - while (!ite_pq_1.empty()) { + while (!pq_1.empty()) { // Set up next level - ite_pq_1.setup_next_level(); + pq_1.setup_next_level(); - const internal::node::label_type out_label = ite_pq_1.current_level(); - internal::node::id_type out_id = 0; + const bdd::label_type out_label = pq_1.current_level(); + bdd::id_type out_id = 0; // Update max 1-level cut - out_arcs->max_1level_cut = std::max(out_arcs->max_1level_cut, ite_pq_1.size()); + out_arcs->max_1level_cut = std::max(out_arcs->max_1level_cut, pq_1.size()); // Process all requests for this level - while (!ite_pq_1.empty_level() || !ite_pq_2.empty() || !ite_pq_3.empty()) { + while (!pq_1.empty_level() || !pq_2.empty() || !pq_3.empty()) { ite_request<2> req; bool with_data_1 = false, with_data_2 = false; // Merge requests from priority queues - if (ite_pq_1.can_pull() - && (ite_pq_2.empty() || ite_pq_1.top().target.first() < ite_pq_2.top().target.second()) - && (ite_pq_3.empty() - || ite_pq_1.top().target.first() < ite_pq_3.top().target.third())) { - req = { - ite_pq_1.top().target, - { { { internal::node::pointer_type::nil(), internal::node::pointer_type::nil() }, - { internal::node::pointer_type::nil(), internal::node::pointer_type::nil() } } }, - ite_pq_1.top().data - }; - - ite_pq_1.pop(); - } else if (!ite_pq_2.empty() - && (ite_pq_3.empty() - || ite_pq_2.top().target.second() < ite_pq_3.top().target.third())) { + if (pq_1.can_pull() + && (pq_2.empty() || pq_1.top().target.first() < pq_2.top().target.second()) + && (pq_3.empty() || pq_1.top().target.first() < pq_3.top().target.third())) { + req = { pq_1.top().target, + { { { bdd::pointer_type::nil(), bdd::pointer_type::nil() }, + { bdd::pointer_type::nil(), bdd::pointer_type::nil() } } }, + pq_1.top().data }; + + pq_1.pop(); + } else if (!pq_2.empty() + && (pq_3.empty() || pq_2.top().target.second() < pq_3.top().target.third())) { with_data_1 = true; - req = { ite_pq_2.top().target, - { ite_pq_2.top().node_carry[0], - { internal::node::pointer_type::nil(), internal::node::pointer_type::nil() } }, - ite_pq_2.top().data }; + req = { pq_2.top().target, + { pq_2.top().node_carry[0], + { bdd::pointer_type::nil(), bdd::pointer_type::nil() } }, + pq_2.top().data }; - ite_pq_2.pop(); + pq_2.pop(); } else { with_data_1 = true; with_data_2 = true; - req = ite_pq_3.top(); - ite_pq_3.pop(); + req = pq_3.top(); + pq_3.pop(); } // Seek request partially in stream - internal::node::pointer_type t_first = req.target.first(); - internal::node::pointer_type t_second = req.target.second(); - internal::node::pointer_type t_third = req.target.third(); + bdd::pointer_type t_first = req.target.first(); + bdd::pointer_type t_second = req.target.second(); + bdd::pointer_type t_third = req.target.third(); - internal::node::pointer_type t_seek = with_data_2 ? t_third - : with_data_1 ? t_second - : t_first; + bdd::pointer_type t_seek = with_data_2 ? t_third : with_data_1 ? t_second : t_first; while (v_if.uid() < t_seek && in_nodes_if.can_pull()) { v_if = in_nodes_if.pull(); } while (v_then.uid() < t_seek && in_nodes_then.can_pull()) { v_then = in_nodes_then.pull(); } @@ -331,49 +314,49 @@ namespace adiar "cannot have forwarded an element, hold two unforwarded items, and still " "need to forward for something"); - internal::node::children_type children_1; - internal::node::children_type children_2; + bdd::node_type::children_type children_1; + bdd::node_type::children_type children_2; if (with_data_1) { if (req.target[0] < t_seek || forward_else) { children_1 = req.node_carry[0]; - internal::node v2 = forward_else ? v_else : v_then; + bdd::node_type v2 = forward_else ? v_else : v_then; children_2 = v2.children(); } else { // if (forward_if || req.target[2] < t_seek) - internal::node v1 = forward_if ? v_if : v_then; + bdd::node_type v1 = forward_if ? v_if : v_then; children_1 = v1.children(); children_2 = req.node_carry[0]; } } else { - internal::node v1 = forward_if ? v_if : v_then; - internal::node v2 = forward_else ? v_else : v_then; + bdd::node_type v1 = forward_if ? v_if : v_then; + bdd::node_type v2 = forward_else ? v_else : v_then; children_1 = v1.children(); children_2 = v2.children(); } - ite_pq_3.push({ req.target, { children_1, children_2 }, req.data }); + pq_3.push({ req.target, { children_1, children_2 }, req.data }); - while (ite_pq_1.can_pull() && ite_pq_1.top().target == req.target) { - ite_pq_3.push({ req.target, { children_1, children_2 }, ite_pq_1.pull().data }); + while (pq_1.can_pull() && pq_1.top().target == req.target) { + pq_3.push({ req.target, { children_1, children_2 }, pq_1.pull().data }); } } else { // got no data and the stream only gave us a single item to forward. - const internal::node v1 = forward_if ? v_if : forward_then ? v_then : v_else; + const bdd::node_type v1 = forward_if ? v_if : forward_then ? v_then : v_else; - const internal::node::children_type v1_children = v1.children(); - ite_pq_2.push({ req.target, { v1_children }, req.data }); + const bdd::node_type::children_type v1_children = v1.children(); + pq_2.push({ req.target, { v1_children }, req.data }); - while (ite_pq_1.can_pull() && ite_pq_1.top().target == req.target) { - ite_pq_2.push({ req.target, { v1_children }, ite_pq_1.pull().data }); + while (pq_1.can_pull() && pq_1.top().target == req.target) { + pq_2.push({ req.target, { v1_children }, pq_1.pull().data }); } } continue; } // Recreate nodes from priority queue carries - internal::node::pointer_type low_if, low_then, low_else, high_if, high_then, high_else; + bdd::pointer_type low_if, low_then, low_else, high_if, high_then, high_else; if (req.target[0].is_terminal() || out_label < req.target[0].label()) { low_if = high_if = req.target[0]; @@ -412,26 +395,26 @@ namespace adiar // Resolve request adiar_assert(out_id < bdd::max_id, "Has run out of ids"); - const internal::node::uid_type out_uid(out_label, out_id++); + const bdd::node_type::uid_type out_uid(out_label, out_id++); - __ite_resolve_request(ite_pq_1, aw, out_uid.as_ptr(false), low_if, low_then, low_else); - __ite_resolve_request(ite_pq_1, aw, out_uid.as_ptr(true), high_if, high_then, high_else); + __ite_resolve_request(pq_1, aw, out_uid.as_ptr(false), low_if, low_then, low_else); + __ite_resolve_request(pq_1, aw, out_uid.as_ptr(true), high_if, high_then, high_else); // Output ingoing arcs - internal::node::pointer_type source = req.data.source; + bdd::pointer_type source = req.data.source; while (true) { internal::arc out_arc = { source, out_uid }; aw.push_internal(out_arc); - if (ite_pq_1.can_pull() && ite_pq_1.top().target == req.target) { - source = ite_pq_1.pull().data.source; - } else if (!ite_pq_2.empty() && ite_pq_2.top().target == req.target) { - source = ite_pq_2.top().data.source; - ite_pq_2.pop(); - } else if (!ite_pq_3.empty() && ite_pq_3.top().target == req.target) { - source = ite_pq_3.top().data.source; - ite_pq_3.pop(); + if (pq_1.can_pull() && pq_1.top().target == req.target) { + source = pq_1.pull().data.source; + } else if (!pq_2.empty() && pq_2.top().target == req.target) { + source = pq_2.top().data.source; + pq_2.pop(); + } else if (!pq_3.empty() && pq_3.top().target == req.target) { + source = pq_3.top().data.source; + pq_3.pop(); } else { break; } @@ -509,6 +492,7 @@ namespace adiar __bdd bdd_ite(const exec_policy& ep, const bdd& f, const bdd& g, const bdd& h) { + // --------------------------------------------------------------------------------------------- // There are multiple cases, where this boils down to an Apply rather than an If-Then-Else. The // bdd_apply uses tuples rather than triples and only two priority queues, so it will run // considerably faster. @@ -523,18 +507,30 @@ namespace adiar // Resolve being given the same underlying file for conditional and a case if (f.file_ptr() == g.file_ptr()) { - return f.is_negated() == g.is_negated() ? bdd_or(f, h) : bdd_and(bdd_not(f), h); - } else if (f.file_ptr() == h.file_ptr()) { + return f.is_negated() == g.is_negated() ? bdd_or(f, h) : bdd_less(f, h); + } + if (f.file_ptr() == h.file_ptr()) { return f.is_negated() == h.is_negated() ? bdd_and(f, g) : bdd_imp(f, g); } + // Resolve being given a terminal conditional + if (bdd_isterminal(f)) { return dd_valueof(f) ? g : h; } + // Resolve being given a terminal in one of the cases - if (bdd_isterminal(g)) { - return bdd_apply(dd_valueof(g) ? f : bdd_not(f), h, dd_valueof(g) ? or_op : and_op); - } else if (bdd_isterminal(h)) { - return bdd_apply(f, g, dd_valueof(h) ? imp_op : and_op); + if (bdd_isterminal(g)) { return dd_valueof(g) ? bdd_or(f, h) : bdd_less(f, h); } + if (bdd_isterminal(h)) { return dd_valueof(h) ? bdd_imp(f, g) : bdd_and(f, g); } + + // --------------------------------------------------------------------------------------------- + // If the levels of 'then' and 'else' are disjoint and the 'if' BDD is above the two others, + // then we can merely zip the 'then' and 'else' BDDs. This is only O((N1+N2+N3)/B) I/Os! + if (bdd_maxvar(f) < bdd_topvar(g) && bdd_maxvar(f) < bdd_topvar(h) + && internal::disjoint_levels(g, h)) { + return __ite_zip_bdds(f, g, h); } + // --------------------------------------------------------------------------------------------- + // From here on forward, we have to do the 3-ary product construction... + // Compute amount of memory available for auxiliary data structures after having opened all // streams. // @@ -603,57 +599,65 @@ namespace adiar #ifdef ADIAR_STATS stats_prod3.lpq.unbucketed += 1u; #endif - return __bdd_ite, - ite_priority_queue_2_t, - ite_priority_queue_3_t>( - ep, - f, - g, - h, - pq_1_internal_memory, - max_pq_1_size, - pq_2_internal_memory, - max_pq_2_size, - pq_3_internal_memory, - max_pq_3_size); + using pq_1_type = ite_priority_queue_1_t<0, internal::memory_mode::Internal>; + using pq_2_type = ite_priority_queue_2_t; + using pq_3_type = ite_priority_queue_3_t; + + return __bdd_ite(ep, + f, + g, + h, + pq_1_internal_memory, + max_pq_1_size, + pq_2_internal_memory, + max_pq_2_size, + pq_3_internal_memory, + max_pq_3_size); + } else if (!external_only && max_pq_1_size <= pq_1_memory_fits && max_pq_2_size <= pq_2_memory_fits && max_pq_3_size <= pq_3_memory_fits) { #ifdef ADIAR_STATS stats_prod3.lpq.internal += 1u; #endif - return __bdd_ite, - ite_priority_queue_2_t, - ite_priority_queue_3_t>( - ep, - f, - g, - h, - pq_1_internal_memory, - max_pq_1_size, - pq_2_internal_memory, - max_pq_2_size, - pq_3_internal_memory, - max_pq_3_size); + using pq_1_type = + ite_priority_queue_1_t; + using pq_2_type = ite_priority_queue_2_t; + using pq_3_type = ite_priority_queue_3_t; + + return __bdd_ite(ep, + f, + g, + h, + pq_1_internal_memory, + max_pq_1_size, + pq_2_internal_memory, + max_pq_2_size, + pq_3_internal_memory, + max_pq_3_size); + } else { #ifdef ADIAR_STATS stats_prod3.lpq.external += 1u; #endif + using pq_1_type = + ite_priority_queue_1_t; + using pq_2_type = ite_priority_queue_2_t; + using pq_3_type = ite_priority_queue_3_t; + const size_t pq_1_memory = aux_available_memory / 3; const size_t pq_2_memory = pq_1_memory; const size_t pq_3_memory = pq_1_memory; - return __bdd_ite, - ite_priority_queue_2_t, - ite_priority_queue_3_t>(ep, - f, - g, - h, - pq_1_memory, - max_pq_1_size, - pq_2_memory, - max_pq_2_size, - pq_3_memory, - max_pq_3_size); + return __bdd_ite(ep, + f, + g, + h, + pq_1_memory, + max_pq_1_size, + pq_2_memory, + max_pq_2_size, + pq_3_memory, + max_pq_3_size); } } diff --git a/test/adiar/bdd/test_if_then_else.cpp b/test/adiar/bdd/test_if_then_else.cpp index 7b91fcb97..4f05147e2 100644 --- a/test/adiar/bdd/test_if_then_else.cpp +++ b/test/adiar/bdd/test_if_then_else.cpp @@ -247,16 +247,16 @@ go_bandit([]() { ; } - describe("Trivial evaluations", [&]() { + describe("O(1) cases", [&]() { // Trivial evaluations by given a terminal - it("should give back first file on if-true (true ? x0 : x1)", [&]() { + it("returns first file on if-true (true ? x0 : x1)", [&]() { __bdd out = bdd_ite(bdd_T, bdd_x0, bdd_x1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x0)); AssertThat(out._negate, Is().False()); }); - it("should give back first file with negation flag on if-true (true ? ~x0 : (~x0))", [&]() { + it("returns first file with negation flag on if-true (true ? ~x0 : (~x0))", [&]() { // Notice, they are equivalent then-and-else cases, but in two // different files. __bdd out = bdd_ite(bdd_T, bdd_not(bdd_x0), bdd_not_x0); @@ -265,14 +265,14 @@ go_bandit([]() { AssertThat(out._negate, Is().True()); }); - it("should give back second file on if-false (false ? x0 : x1)", [&]() { + it("returns second file on if-false (false ? x0 : x1)", [&]() { __bdd out = bdd_ite(bdd_F, bdd_x0, bdd_x1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); AssertThat(out._negate, Is().False()); }); - it("should give back second file on if-false (false ? (~x1) : ~x1)", [&]() { + it("returns second file on if-false (false ? (~x1) : ~x1)", [&]() { // Notice, they are equivalent then-and-else cases, but in two // different files. __bdd out = bdd_ite(bdd_F, bdd_not_x1, bdd_not(bdd_x1)); @@ -282,14 +282,14 @@ go_bandit([]() { }); // Trivial inputs with duplicate file inputs - it("should return 'then' file if 'else' file is the same [1]", [&]() { + it("returns 'then' file if 'else' file is the same [1]", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_x1); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); AssertThat(out._negate, Is().False()); }); - it("should return 'then' file if 'else' file is the same [2]", [&]() { + it("returns 'then' file if 'else' file is the same [2]", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_not(bdd_x1), bdd_not(bdd_x1)); AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(bdd_x1)); @@ -297,8 +297,8 @@ go_bandit([]() { }); }); - describe("Inputs boiling down to an apply", [&]() { - it("should create XNOR of x0 and x1 (x0 ? x1 : ~x1) due to same file", [&]() { + describe("'bdd_apply(...)' cases", [&]() { + it("creates XNOR of x0 and x1 (x0 ? x1 : ~x1) due to same file", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_not(bdd_x1)); arc_test_stream arcs(out); @@ -347,7 +347,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should create XNOR of x0 and ~x1 (x0 ? ~x1 : x1) due to same file", [&]() { + it("creates XNOR of x0 and ~x1 (x0 ? ~x1 : x1) due to same file", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_not(bdd_x1), bdd_x1); arc_test_stream arcs(out); @@ -396,7 +396,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should create OR of x0 and x1 (x0 ? x0 : x1) due to same file", [&]() { + it("creates OR of x0 and x1 (x0 ? x0 : x1) due to same file", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x0, bdd_x1); arc_test_stream arcs(out); @@ -438,7 +438,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should create AND of x0 (negated) and x1 (x0 ? ~x0 : x1) due to same file", [&]() { + it("creates LESS of x0 (negated) and x1 (x0 ? ~x0 : x1) due to same file", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_not(bdd_x0), bdd_x1); arc_test_stream arcs(out); @@ -480,7 +480,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should create AND of x0 and x1 (x0 ? x1 : x0) due to same file", [&]() { + it("creates AND of x0 and x1 (x0 ? x1 : x0) due to same file", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_x0); arc_test_stream arcs(out); @@ -522,7 +522,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should create IMPLIES of x0 and x1 (x0 ? x1 : ~x0) due to same file", [&]() { + it("creates IMPLIES of x0 and x1 (x0 ? x1 : ~x0) due to same file", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_not(bdd_x0)); arc_test_stream arcs(out); @@ -564,7 +564,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should create OR of x0 and x1 (x0 ? T : x1)", [&]() { + it("creates OR of x0 and x1 (x0 ? T : x1)", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_T, bdd_x1); arc_test_stream arcs(out); @@ -606,7 +606,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should create AND of x0 (negated) and x1 (x0 ? F : x1)", [&]() { + it("creates AND of x0 (negated) and x1 (x0 ? F : x1)", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_F, bdd_x1); arc_test_stream arcs(out); @@ -648,7 +648,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should create IMPLIES of x0 and x1 (x0 ? x1 : T)", [&]() { + it("creates IMPLIES of x0 and x1 (x0 ? x1 : T)", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_T); arc_test_stream arcs(out); @@ -688,7 +688,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should create AND of x0 and x1 (x0 ? x1 : F)", [&]() { + it("creates AND of x0 and x1 (x0 ? x1 : F)", [&]() { __bdd out = bdd_ite(bdd_x0, bdd_x1, bdd_F); arc_test_stream arcs(out); @@ -731,8 +731,8 @@ go_bandit([]() { }); }); - describe("Inputs that require the cross-product of all three BDDs", [&]() { - it("should compute x0 ? ~x1 : x1", [&]() { + describe("'prod3(...)' cases", [&]() { + it("computes x0 ? ~x1 : x1", [&]() { /* // (x0, ~x1, x1) ---- x0 // / \ @@ -791,7 +791,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute x1 ? ~x0 : x0", [&]() { + it("computes x1 ? ~x0 : x0", [&]() { /* // (x1, ~x0, x0) ---- x0 // / \ @@ -849,7 +849,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute x1 ? x0 : ~x0", [&]() { + it("computes x1 ? x0 : ~x0", [&]() { /* // (x1, x0, ~x0) ---- x0 // / \ @@ -993,7 +993,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute x3 ? (x1 & x2) : bdd_1", [&]() { + it("computes x3 ? (x1 & x2) : bdd_1", [&]() { shared_levelized_file bdd_x3; /* // 1 ---- x3 @@ -1150,7 +1150,7 @@ go_bandit([]() { Is().EqualTo(3u)); }); - it("should compute bdd_3 ? bdd_4 : bdd_5", [&]() { + it("computes bdd_3 ? bdd_4 : bdd_5", [&]() { /* // (1,1,1) ---- x0 // ______/ \______ @@ -1259,7 +1259,7 @@ go_bandit([]() { Is().EqualTo(4u)); }); - it("should compute bdd_6 ? x0^x2 : bdd_not_6", [&]() { + it("computes bdd_6 ? x0^x2 : bdd_not_6", [&]() { /* bdd_x0_xor_x2 // _1_ ---- x1 // / \ @@ -1338,7 +1338,7 @@ go_bandit([]() { Is().EqualTo(4u)); }); - it("should compute bdd_not_6 ? bdd_6 : x0^x2", [&]() { + it("computes bdd_not_6 ? bdd_6 : x0^x2", [&]() { /* bdd_x0_xor_x2 // _1_ ---- x1 // / \ @@ -1417,7 +1417,7 @@ go_bandit([]() { Is().EqualTo(1u)); }); - it("should compute ~(x0^x2) ? ~x2 : bdd_1", [&]() { + it("computes ~(x0^x2) ? ~x2 : bdd_1", [&]() { shared_levelized_file bdd_x0_xnor_x2; /* // _1_ @@ -1543,7 +1543,7 @@ go_bandit([]() { Is().EqualTo(5u)); }); - it("should compute (x1^x2) ? bdd_1 : bdd_2", [&]() { + it("computes (x1^x2) ? bdd_1 : bdd_2", [&]() { shared_levelized_file bdd_x1_xor_x2_2; /* // _1_ ---- x1 @@ -1673,7 +1673,7 @@ go_bandit([]() { Is().EqualTo(6u)); }); - it("should compute (~x0 & ~x1 & x2) ? bdd_2 : bdd_4", [&]() { + it("computes (~x0 & ~x1 & x2) ? bdd_2 : bdd_4", [&]() { shared_levelized_file bdd_if; /* // 1 ---- x0 @@ -1793,7 +1793,7 @@ go_bandit([]() { Is().EqualTo(4u)); }); - it("should compute (x0 | (x1 & x2)) ? bdd_8 : bdd_7", [&]() { + it("computes (x0 | (x1 & x2)) ? bdd_8 : bdd_7", [&]() { shared_levelized_file bdd_if; /* // 1 ---- x0 @@ -1898,7 +1898,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should compute bdd_6 ? bdd_4 : bdd_2", [&]() { + it("computes bdd_6 ? bdd_4 : bdd_2", [&]() { /* // (1,1,1) ---- x0 // __________/ \___________ @@ -2003,8 +2003,8 @@ go_bandit([]() { }); }); - describe("Zipping", [&]() { - it("should merely zip disjunct levels if possible [1]", [&]() { + describe("O(N/B) zipping cases", [&]() { + it("merely zips disjunct levels if possible [1]", [&]() { shared_levelized_file bdd_x1_and_x3; /* // 1 ---- x1 @@ -2081,7 +2081,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should merely zip disjunct levels if possible [2]", [&]() { + it("merely zips disjunct levels if possible [2]", [&]() { shared_levelized_file bdd_then; /* // _1_ ---- x2 @@ -2344,7 +2344,7 @@ go_bandit([]() { AssertThat(bdd_iscanonical(out_3), Is().True()); }); - it("should not zip if bdd_then is not beyond max_var of bdd_if", [&]() { + it("does not zip if bdd_then is not beyond max_var of bdd_if", [&]() { __bdd out = bdd_ite(bdd_x1, bdd_x0, bdd_x2); arc_test_stream arcs(out); @@ -2403,7 +2403,7 @@ go_bandit([]() { Is().EqualTo(2u)); }); - it("should not zip if bdd_else is not beyond max_var of bdd_if", [&]() { + it("does not zip if bdd_else is not beyond max_var of bdd_if", [&]() { __bdd out = bdd_ite(bdd_x1, bdd_x2, bdd_x0); arc_test_stream arcs(out); From 141db3b138dff8c49058985619ee87cf00099292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Wed, 19 Jun 2024 15:07:51 +0200 Subject: [PATCH 20/30] Fix conversion of negated BDD terminal into ZDD throws exception --- src/adiar/zdd/zdd.cpp | 4 +- .../internal/algorithms/test_convert.cpp | 54 ++++++++++--------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/adiar/zdd/zdd.cpp b/src/adiar/zdd/zdd.cpp index ec6403c0f..7d2d9bef5 100644 --- a/src/adiar/zdd/zdd.cpp +++ b/src/adiar/zdd/zdd.cpp @@ -47,9 +47,7 @@ namespace adiar zdd::zdd(const shared_node_file_type& A, bool negate) : internal::dd(A, negate) - { - if (negate) { throw invalid_argument("ZDDs cannot be negated"); } - } + {} zdd::zdd(const zdd& A) : internal::dd(A) diff --git a/test/adiar/internal/algorithms/test_convert.cpp b/test/adiar/internal/algorithms/test_convert.cpp index 7e66e4e50..84e92f2f4 100644 --- a/test/adiar/internal/algorithms/test_convert.cpp +++ b/test/adiar/internal/algorithms/test_convert.cpp @@ -94,32 +94,18 @@ go_bandit([]() { }); describe("bdd_from(const zdd&, ForwardIt, ForwardIt)", [&]() { - it("returns F terminal on Ø with dom = Ø", [&]() { + it("returns same file for F terminal on Ø with dom = Ø", [&]() { __bdd out = bdd_from(zdd_F, dom_empty.begin(), dom_empty.end()); - node_test_stream out_nodes(out); - - AssertThat(out_nodes.can_pull(), Is().True()); - AssertThat(out_nodes.pull(), Is().EqualTo(node(false))); - - AssertThat(out_nodes.can_pull(), Is().False()); - - level_info_test_stream ms(out); - AssertThat(ms.can_pull(), Is().False()); + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(zdd_F.file_ptr())); + AssertThat(out._negate, Is().False()); }); - it("returns T terminal on { Ø } with dom = Ø", [&]() { + it("returns same file for T terminal on { Ø } with dom = Ø", [&]() { __bdd out = bdd_from(zdd_T, dom_empty.begin(), dom_empty.end()); - node_test_stream out_nodes(out); - - AssertThat(out_nodes.can_pull(), Is().True()); - AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); - - AssertThat(out_nodes.can_pull(), Is().False()); - - level_info_test_stream ms(out); - AssertThat(ms.can_pull(), Is().False()); + AssertThat(out.get<__bdd::shared_node_file_type>(), Is().EqualTo(zdd_T.file_ptr())); + AssertThat(out._negate, Is().False()); }); it("returns F terminal on Ø with dom = { 0,1,2 }", [&]() { @@ -1161,10 +1147,27 @@ go_bandit([]() { it("returns Ø on F terminal with dom = Ø", [&]() { __zdd out = zdd_from(bdd_F, dom_empty.begin(), dom_empty.end()); + AssertThat(out.get<__zdd::shared_node_file_type>(), Is().EqualTo(bdd_F.file_ptr())); + AssertThat(out._negate, Is().False()); + }); + + it("returns { Ø } on T terminal with dom = Ø", [&]() { + __zdd out = zdd_from(bdd_T, dom_empty.begin(), dom_empty.end()); + + AssertThat(out.get<__zdd::shared_node_file_type>(), Is().EqualTo(bdd_T.file_ptr())); + AssertThat(out._negate, Is().False()); + }); + + it("returns Ø on negated F terminal with dom = Ø", [&]() { + __zdd out = zdd_from(bdd_not(bdd_F), dom_empty.begin(), dom_empty.end()); + + AssertThat(out.get<__zdd::shared_node_file_type>(), Is().EqualTo(bdd_F.file_ptr())); + AssertThat(out._negate, Is().True()); + node_test_stream out_nodes(out); AssertThat(out_nodes.can_pull(), Is().True()); - AssertThat(out_nodes.pull(), Is().EqualTo(node(false))); + AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); AssertThat(out_nodes.can_pull(), Is().False()); @@ -1172,13 +1175,16 @@ go_bandit([]() { AssertThat(ms.can_pull(), Is().False()); }); - it("returns { Ø } on T terminal with dom = Ø", [&]() { - __zdd out = zdd_from(bdd_T, dom_empty.begin(), dom_empty.end()); + it("returns { Ø } on negated T terminal with dom = Ø", [&]() { + __zdd out = zdd_from(bdd_not(bdd_T), dom_empty.begin(), dom_empty.end()); + + AssertThat(out.get<__zdd::shared_node_file_type>(), Is().EqualTo(bdd_T.file_ptr())); + AssertThat(out._negate, Is().True()); node_test_stream out_nodes(out); AssertThat(out_nodes.can_pull(), Is().True()); - AssertThat(out_nodes.pull(), Is().EqualTo(node(true))); + AssertThat(out_nodes.pull(), Is().EqualTo(node(false))); AssertThat(out_nodes.can_pull(), Is().False()); From 5121d15a08e5ea00a9eeefc9da840c8983c99cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Wed, 19 Jun 2024 15:10:42 +0200 Subject: [PATCH 21/30] Fix descriptions for convert algorithm groups --- test/adiar/internal/algorithms/test_convert.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/adiar/internal/algorithms/test_convert.cpp b/test/adiar/internal/algorithms/test_convert.cpp index 84e92f2f4..b3739c45a 100644 --- a/test/adiar/internal/algorithms/test_convert.cpp +++ b/test/adiar/internal/algorithms/test_convert.cpp @@ -89,7 +89,7 @@ go_bandit([]() { bdd bdd_x0(nf_x0); bdd bdd_x2(nf_x2); - describe("bdd_from(const zdd&, const generator_func&)", [&]() { + describe("bdd_from(const zdd&, const generator<...>&)", [&]() { // TODO }); @@ -1139,7 +1139,7 @@ go_bandit([]() { }); }); - describe("zdd_from(const bdd&, const generator_func&)", [&]() { + describe("zdd_from(const bdd&, const generator<...>&)", [&]() { // TODO }); From d345743bf9d1ab7226d5cfab1beb7d7d47243ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Thu, 20 Jun 2024 09:06:24 +0200 Subject: [PATCH 22/30] Add missing unit tests for on-the-fly negation --- test/adiar/internal/io/test_node_file.cpp | 27 ++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/test/adiar/internal/io/test_node_file.cpp b/test/adiar/internal/io/test_node_file.cpp index b0e25be91..39cc21622 100644 --- a/test/adiar/internal/io/test_node_file.cpp +++ b/test/adiar/internal/io/test_node_file.cpp @@ -12,9 +12,8 @@ go_bandit([]() { }); describe("node_writer [ << ] + node_file::stats", []() { - // ------------------------------------------------------------------- - // Canonical node files where the max 1-level cut and max 2-level cuts - // are the same. + // ------------------------------------------------------------------------------------------- + // Canonical node files where the max 1-level cut and max 2-level cuts are the same. /* F */ @@ -145,8 +144,8 @@ go_bandit([]() { << node(42, node::max_id - 1, node::pointer_type(true), node::pointer_type(false)) << node(21, node::max_id, - node::pointer_type(42, node::pointer_type::max_id), - node::pointer_type(42, node::pointer_type::max_id - 1)); + node::pointer_type(42, node::max_id), + node::pointer_type(42, node::max_id - 1)); } /* @@ -1459,6 +1458,24 @@ go_bandit([]() { AssertThat(nra.at(B_n6.uid()), Is().EqualTo(B_n6)); AssertThat(nra.at(B_n7.uid()), Is().EqualTo(B_n7)); }); + + it("negates nodes on-the-fly [idx]", [&]() { + node_random_access nra(nf_B, true); + nra.setup_next_level(2u); + + AssertThat(nra.at(0u), Is().EqualTo(!B_n3)); + AssertThat(nra.at(1u), Is().EqualTo(!B_n4)); + AssertThat(nra.at(2u), Is().EqualTo(!B_n5)); + }); + + it("negates nodes on-the-fly [uid]", [&]() { + node_random_access nra(nf_B, true); + nra.setup_next_level(2u); + + AssertThat(nra.at(B_n3.uid()), Is().EqualTo(!B_n3)); + AssertThat(nra.at(B_n4.uid()), Is().EqualTo(!B_n4)); + AssertThat(nra.at(B_n5.uid()), Is().EqualTo(!B_n5)); + }); }); describe(".root()", [&]() { From db4c3060ef4b27b3d75c0c7eff5afc4982365ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 09:11:31 +0200 Subject: [PATCH 23/30] Keep Assembler output for 'playground' target to investigate low-level code --- src/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 69b90f5b7..14f7b2db9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,3 +4,8 @@ add_subdirectory (adiar) # Setup MAIN target add_executable (adiar_playground playground.cpp) target_link_libraries(adiar_playground adiar) + +# Dump assembly output too (if GCC) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set_target_properties(adiar_playground PROPERTIES COMPILE_FLAGS "-save-temps") +endif () From 88819d4070b2f4da6acadfb6705ef12119dd974e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Thu, 20 Jun 2024 13:52:12 +0200 Subject: [PATCH 24/30] Make 'shift_replace(const ptr_uint64&)' branchless (Thanks, Lasse!) --- src/adiar/internal/data_types/ptr.h | 30 ++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/adiar/internal/data_types/ptr.h b/src/adiar/internal/data_types/ptr.h index 28353836e..3b9a9b812 100644 --- a/src/adiar/internal/data_types/ptr.h +++ b/src/adiar/internal/data_types/ptr.h @@ -11,8 +11,8 @@ namespace adiar::internal // TODO (ADD (32-bit)): // Template 'ptr_uint64' with 'terminal_t' of how to interpret the bits of a terminal. To this - // end, one wants to use 'std::bit_cast' in the internal logic. Use 'static_assert' to ensure - // the desired type indeed fits into 62 bits of memory. + // end, one wants to use 'std::bit_cast' (C++20) in the internal logic. Use 'static_assert' to + // ensure the desired type indeed fits into 62 bits of memory. // TODO (ADD (64-bit)): // TODO (10+ TiB Decision Diagrams): @@ -854,21 +854,25 @@ namespace adiar::internal inline ptr_uint64 shift_replace(const ptr_uint64& p, const ptr_uint64::signed_level_type levels) { - // TODO (optimisation): Make this a branch-less computation! - if (levels == 0 || !p.is_node()) { return p; } + // Evil type hacks (Thanks, Quake III) + const ptr_uint64::level_type p_level__unsigned = p.level(); + const ptr_uint64::signed_level_type p_level__signed = + (*reinterpret_cast(&p_level__unsigned)); - // TODO (optimisation): Replace static_cast<...> with dynamic_cast<...> if always safe. - const bool subtract = levels < 0; - const ptr_uint64::level_type abs_levels = - static_cast(subtract ? -levels : levels); + const ptr_uint64::signed_level_type p_new_level__signed = p_level__signed + levels; + const ptr_uint64::level_type p_new_level__unsigned = + (*reinterpret_cast(&p_new_level__signed)); - adiar_assert(subtract ? (abs_levels <= p.label()) - : (p.label() + abs_levels <= ptr_uint64::max_label)); + // Shift levels back and combine with other bits + const ptr_uint64::raw_type level_bits = + static_cast(p_new_level__unsigned) << ptr_uint64::level_shift; - const ptr_uint64::raw_type shifted_abs_levels = static_cast(abs_levels) - << ptr_uint64::level_shift; + constexpr ptr_uint64::raw_type non_levels_mask = + ~(static_cast(ptr_uint64::max_level) << ptr_uint64::level_shift); + const ptr_uint64::raw_type other_bits = p._raw & non_levels_mask; - return subtract ? (p._raw - shifted_abs_levels) : (p._raw + shifted_abs_levels); + // Use above computation (cmove), if it is a node. + return p.is_node() ? (level_bits | other_bits) : p._raw; } /* ======================================== CONVERSION ======================================== */ From 78999297b78f0e5c7e17dd8dbc9544ad0161e3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 09:27:17 +0200 Subject: [PATCH 25/30] Move befriending of 'essential(...)' into a more reasonable place --- src/adiar/internal/data_types/ptr.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/adiar/internal/data_types/ptr.h b/src/adiar/internal/data_types/ptr.h index 3b9a9b812..6c24c86c3 100644 --- a/src/adiar/internal/data_types/ptr.h +++ b/src/adiar/internal/data_types/ptr.h @@ -220,6 +220,9 @@ namespace adiar::internal friend ptr_uint64 unflag(const ptr_uint64& p); + + friend ptr_uint64 + essential(const ptr_uint64& p); //////////////////////////////////////////////////////////////////////////////////////////////// public: @@ -379,13 +382,6 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// using out_idx_type = uint8_t; - private: - //////////////////////////////////////////////////////////////////////////////////////////////// - // befriend flag modifying functions that need access to protected values. - friend ptr_uint64 - essential(const ptr_uint64& p); - //////////////////////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Number of out-going edges from a node From 5f30f5aeeb54311c0b3def6ef5477cb22a95279f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 09:27:45 +0200 Subject: [PATCH 26/30] Add 'cnot(const ptr_uint64&, bool)' for a more branch-less on-the-fly negation --- src/adiar/internal/data_types/ptr.h | 20 ++++++++++++++ test/adiar/internal/data_types/test_ptr.cpp | 30 +++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/adiar/internal/data_types/ptr.h b/src/adiar/internal/data_types/ptr.h index 6c24c86c3..5bedd4f5c 100644 --- a/src/adiar/internal/data_types/ptr.h +++ b/src/adiar/internal/data_types/ptr.h @@ -512,6 +512,12 @@ namespace adiar::internal /* ======================================== TERMINALS ======================================= */ + //////////////////////////////////////////////////////////////////////////////////////////////// + // befriend terminal modifying functions that need access to protected values. + friend ptr_uint64 + cnot(const ptr_uint64& p, const bool negate); + //////////////////////////////////////////////////////////////////////////////////////////////// + public: //////////////////////////////////////////////////////////////////////////////////////////////// /// When the terminal flag is set, then we interpret the middle bits as the value of the @@ -804,6 +810,20 @@ namespace adiar::internal : (p._raw & ~ptr_uint64::flag_bit); } + /* ========================================= TERMINAL ========================================= */ + + ////////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Negates the content of `p` if it is a terminal and the `negate` flag is set to true. + ////////////////////////////////////////////////////////////////////////////////////////////////// + inline ptr_uint64 + cnot(const ptr_uint64& p, const bool negate) + { + const ptr_uint64::raw_type shifted_negate = + static_cast(negate) << ptr_uint64::data_shift; + + return p.is_terminal() ? p._raw ^ shifted_negate : p._raw; + } + /* =========================================== LEVEL ========================================== */ ////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/test/adiar/internal/data_types/test_ptr.cpp b/test/adiar/internal/data_types/test_ptr.cpp index e626f62d9..305048cf8 100644 --- a/test/adiar/internal/data_types/test_ptr.cpp +++ b/test/adiar/internal/data_types/test_ptr.cpp @@ -407,6 +407,36 @@ go_bandit([]() { AssertThat(essential(flag(p)), Is().EqualTo(p)); }); }); + + describe("cnot(...)", []() { + it("leaves 'false' terminal as-is if flag is not set", [&]() { + const ptr_uint64 p = ptr_uint64(false); + + AssertThat(cnot(p, false), Is().EqualTo(p)); + AssertThat(cnot(flag(p), false), Is().EqualTo(flag(p))); + }); + + it("leaves 'true' terminal as-is if flag is not set", [&]() { + const ptr_uint64 p = ptr_uint64(true); + + AssertThat(cnot(p, false), Is().EqualTo(p)); + AssertThat(cnot(flag(p), false), Is().EqualTo(flag(p))); + }); + + it("negates 'false' terminal if flag is set", [&]() { + const ptr_uint64 p = ptr_uint64(false); + + AssertThat(cnot(p, true), Is().EqualTo(ptr_uint64(true))); + AssertThat(cnot(flag(p), true), Is().EqualTo(flag(ptr_uint64(true)))); + }); + + it("negates 'true' terminal if flag is set", [&]() { + const ptr_uint64 p = ptr_uint64(true); + + AssertThat(cnot(p, true), Is().EqualTo(ptr_uint64(false))); + AssertThat(cnot(flag(p), true), Is().EqualTo(flag(ptr_uint64(false)))); + }); + }); }); describe("internal nodes", [&]() { From 33b4147a0da8239389d003410f0cf93ba96ee964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 09:38:57 +0200 Subject: [PATCH 27/30] Clean up in tests for 'node' class --- test/adiar/internal/data_types/test_node.cpp | 66 ++++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/test/adiar/internal/data_types/test_node.cpp b/test/adiar/internal/data_types/test_node.cpp index a3d1e2185..6a6b84dff 100644 --- a/test/adiar/internal/data_types/test_node.cpp +++ b/test/adiar/internal/data_types/test_node.cpp @@ -6,9 +6,9 @@ go_bandit([]() { const ptr_uint64 terminal_T = ptr_uint64(true); describe("node", [&]() { - it("should be a POD", [&]() { AssertThat(std::is_pod::value, Is().True()); }); + it("is a POD", [&]() { AssertThat(std::is_pod::value, Is().True()); }); - it("should take up 24 bytes of memory", [&]() { + it("takes up 24 bytes of memory", [&]() { const ptr_uint64 node_ptr = ptr_uint64(42, 2); const node n = node(1u, 8u, node_ptr, terminal_F); @@ -16,7 +16,7 @@ go_bandit([]() { }); describe("node(...), .label(), .id(), .low(), .high()", [&]() { - it("should create node [label_type, id_type, ptr_uint64, ptr_uint64] [1]", [&]() { + it("creates node [label_type, id_type, ptr_uint64, ptr_uint64] [1]", [&]() { const node n = node(3u, 12u, terminal_F, terminal_T); AssertThat(n.uid(), Is().EqualTo(ptr_uint64(3, 12))); AssertThat(n.label(), Is().EqualTo(3u)); @@ -28,7 +28,7 @@ go_bandit([]() { AssertThat(n.high(), Is().EqualTo(terminal_T)); }); - it("should create node [label_type, id_type, ptr_uint64, ptr_uint64] [2]", [&]() { + it("creates node [label_type, id_type, ptr_uint64, ptr_uint64] [2]", [&]() { const node n = node(3u, 42u, terminal_T, terminal_F); AssertThat(n.uid(), Is().EqualTo(ptr_uint64(3, 42))); AssertThat(n.label(), Is().EqualTo(3u)); @@ -40,7 +40,7 @@ go_bandit([]() { AssertThat(n.high(), Is().EqualTo(terminal_F)); }); - it("should create node [label_type, id_type, node&, node&]", [&]() { + it("creates node [label_type, id_type, node&, node&]", [&]() { const node n_child1 = node(3u, 12u, terminal_F, terminal_T); const node n_child2 = node(3u, 42u, terminal_T, terminal_F); @@ -55,7 +55,7 @@ go_bandit([]() { AssertThat(n.high(), Is().EqualTo(n_child2.uid())); }); - it("should create node [label_type, id_type, node&, ptr_uint64]", [&]() { + it("creates node [label_type, id_type, node&, ptr_uint64]", [&]() { const node n_child = node(2u, 2u, terminal_F, terminal_T); const node n = node(1u, 7u, terminal_T, n_child); @@ -69,7 +69,7 @@ go_bandit([]() { AssertThat(n.high(), Is().EqualTo(n_child.uid())); }); - it("should create node [label_type, id_type, ptr_uint64, node&]", [&]() { + it("creates node [label_type, id_type, ptr_uint64, node&]", [&]() { const node n_child = node(2u, 2u, terminal_F, terminal_T); const node n = node(0u, 3u, terminal_T, n_child); @@ -156,7 +156,7 @@ go_bandit([]() { }); describe("comparators [node]", [&]() { - it("should primarily sort by label", [&]() { + it("sorts primarily by label", [&]() { const node node_1 = node(1u, 2u, terminal_F, terminal_T); const node node_2 = node(2u, 1u, terminal_T, terminal_F); @@ -166,7 +166,7 @@ go_bandit([]() { AssertThat(node_2, Is().GreaterThanOrEqualTo(node_1)); }); - it("should secondly sort by id", [&]() { + it("sorts secondly by id", [&]() { const node node_1 = node(2u, 1u, terminal_F, terminal_T); const node node_2 = node(2u, 2u, terminal_T, terminal_F); @@ -176,7 +176,7 @@ go_bandit([]() { AssertThat(node_2, Is().GreaterThanOrEqualTo(node_1)); }); - it("should thirdly sort by children [1]", [&]() { + it("sorts thirdly by children [1]", [&]() { const node node_1 = node(2u, 0u, terminal_F, terminal_T); const node node_2 = node(2u, 0u, terminal_T, terminal_F); @@ -186,7 +186,7 @@ go_bandit([]() { AssertThat(node_2, Is().GreaterThanOrEqualTo(node_1)); }); - it("should thirdly sort by children [2]", [&]() { + it("sorts thirdly by children [2]", [&]() { const node node_1 = node(2u, 0u, terminal_T, terminal_F); const node node_2 = node(2u, 0u, terminal_T, terminal_T); @@ -196,7 +196,7 @@ go_bandit([]() { AssertThat(node_2, Is().GreaterThanOrEqualTo(node_1)); }); - it("should (not) provide an ordering when equal", [&]() { + it("does (not) provide an ordering when equal", [&]() { const node node_1 = node(2u, 1u, terminal_F, terminal_T); const node node_2 = node(2u, 1u, terminal_F, terminal_T); @@ -207,7 +207,7 @@ go_bandit([]() { AssertThat(node_2, Is().GreaterThanOrEqualTo(node_1)); }); - it("should be equal by if uid, low, and high agree [1]", [&]() { + it("is equal by if uid, low, and high agree [1]", [&]() { const node node_1_v1 = node(42u, 2u, terminal_F, terminal_T); const node node_1_v2 = node(42u, 2u, terminal_F, terminal_T); @@ -215,7 +215,7 @@ go_bandit([]() { AssertThat(node_1_v1 != node_1_v2, Is().False()); }); - it("should be equal by if uid, low, and high agree [2]", [&]() { + it("is equal by if uid, low, and high agree [2]", [&]() { const node node_1_v1 = node(0u, 0u, terminal_F, terminal_F); const node node_1_v2 = node(0u, 0u, terminal_F, terminal_F); @@ -223,7 +223,7 @@ go_bandit([]() { AssertThat(node_1_v1 != node_1_v2, Is().False()); }); - it("should be unequal if uid mismatches [1]", [&]() { + it("is unequal if uid mismatches [1]", [&]() { const node node_1 = node(42u, 2u, terminal_F, terminal_T); const node node_2 = node(42u, 1u, terminal_F, terminal_T); @@ -231,7 +231,7 @@ go_bandit([]() { AssertThat(node_1 != node_2, Is().True()); }); - it("should be unequal if uid mismatches [2]", [&]() { + it("is unequal if uid mismatches [2]", [&]() { const node node_1 = node(42u, 2u, terminal_F, terminal_T); const node node_2 = node(21u, 2u, terminal_F, terminal_T); @@ -239,7 +239,7 @@ go_bandit([]() { AssertThat(node_1 != node_2, Is().True()); }); - it("should be unequal if uid mismatches [3]", [&]() { + it("is unequal if uid mismatches [3]", [&]() { const node node_1 = node(42u, 2u, terminal_F, terminal_T); const node node_2 = node(21u, 8u, terminal_F, terminal_T); @@ -247,7 +247,7 @@ go_bandit([]() { AssertThat(node_1 != node_2, Is().True()); }); - it("should be unequal if low mismatches [1]", [&]() { + it("is unequal if low mismatches [1]", [&]() { const node node_1 = node(42u, 2u, terminal_F, terminal_T); const node node_2 = node(42u, 2u, terminal_T, terminal_T); @@ -255,7 +255,7 @@ go_bandit([]() { AssertThat(node_1 != node_2, Is().True()); }); - it("should be unequal if high mismatches [1]", [&]() { + it("is unequal if high mismatches [1]", [&]() { const node node_1 = node(42u, 2u, terminal_F, terminal_T); const node node_2 = node(42u, 2u, terminal_F, terminal_F); @@ -265,7 +265,7 @@ go_bandit([]() { }); describe("comparators [uid]", [&]() { - it("should primarily sort by label [ 1]", [&]() { + it("sorts primarily by label [ 1]", [&]() { const node n = node(0u, 1u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(1u, 0u); @@ -275,7 +275,7 @@ go_bandit([]() { AssertThat(u, Is().GreaterThanOrEqualTo(n)); }); - it("should primarily sort by label [!1]", [&]() { + it("sorts primarily by label [!1]", [&]() { const node n = node(0u, 1u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(1u, 0u); @@ -285,7 +285,7 @@ go_bandit([]() { AssertThat(n, Is().Not().GreaterThanOrEqualTo(u)); }); - it("should primarily sort by label [ 2]", [&]() { + it("sorts primarily by label [ 2]", [&]() { const node n = node(21u, 8u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(42u, 2u); @@ -295,7 +295,7 @@ go_bandit([]() { AssertThat(u, Is().GreaterThanOrEqualTo(n)); }); - it("should primarily sort by label [ 3]", [&]() { + it("sorts primarily by label [ 3]", [&]() { const node n = node(1u, 1u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(0u, 2u); @@ -305,7 +305,7 @@ go_bandit([]() { AssertThat(n, Is().GreaterThanOrEqualTo(u)); }); - it("should primarily sort by label [ 4]", [&]() { + it("sorts primarily by label [ 4]", [&]() { const node n = node(42u, 0u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(21u, 8u); @@ -315,7 +315,7 @@ go_bandit([]() { AssertThat(n, Is().GreaterThanOrEqualTo(u)); }); - it("should primarily sort by label [!4]", [&]() { + it("sorts primarily by label [!4]", [&]() { const node n = node(42u, 0u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(21u, 8u); @@ -325,7 +325,7 @@ go_bandit([]() { AssertThat(u, Is().Not().GreaterThanOrEqualTo(n)); }); - it("should secondly sort by id [ 1]", [&]() { + it("sorts secondly by id [ 1]", [&]() { const node n = node(42u, 0u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(42u, 1u); @@ -335,7 +335,7 @@ go_bandit([]() { AssertThat(u, Is().GreaterThanOrEqualTo(n)); }); - it("should secondly sort by id [ 2]", [&]() { + it("sorts secondly by id [ 2]", [&]() { const node n = node(42u, 1u, terminal_F, terminal_T); const node::uid_type u = node::uid_type(42u, 0u); @@ -346,29 +346,29 @@ go_bandit([]() { }); }); - describe("not ( ~ )", [&]() { - it("should leave node_ptr children unchanged", [&]() { + describe("not ( ! )", [&]() { + it("leaves node_ptr children unchanged", [&]() { const node n = node(2u, 2u, ptr_uint64(42, 3), ptr_uint64(8, 2)); AssertThat(!n, Is().EqualTo(n)); }); - it("should negate terminal_ptr child", [&]() { + it("negates terminal_ptr child", [&]() { const node n = node(2u, 2u, terminal_F, ptr_uint64(8, 2)); AssertThat(!n, Is().EqualTo(node(2, 2, terminal_T, ptr_uint64(8, 2)))); }); - it("should negate terminal_ptr children while preserving flags", [&]() { + it("negates terminal_ptr children while preserving flags", [&]() { const node n = node(2u, 2u, terminal_F, flag(terminal_T)); AssertThat(!n, Is().EqualTo(node(2, 2, terminal_T, flag(terminal_F)))); }); - it("should negate 'false' terminal node", + it("negates 'false' terminal node", [&]() { AssertThat(!node(false), Is().EqualTo(node(true))); }); - it("should negate 'true' terminal node", + it("negates 'true' terminal node", [&]() { AssertThat(!node(true), Is().EqualTo(node(false))); }); }); }); From 7cda4ecfe19b9f9490d16618d50df07478cd3759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 09:39:19 +0200 Subject: [PATCH 28/30] Add 'cnot(const node&, bool)' for more branch-less on-the-fly negation --- src/adiar/internal/data_types/node.h | 11 +++++ test/adiar/internal/data_types/test_node.cpp | 50 ++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/adiar/internal/data_types/node.h b/src/adiar/internal/data_types/node.h index 7cc415147..c5f19e5f4 100644 --- a/src/adiar/internal/data_types/node.h +++ b/src/adiar/internal/data_types/node.h @@ -488,6 +488,17 @@ namespace adiar::internal return u >= n.uid(); } + /* ========================================== TERMINAL ======================================== */ + inline node + cnot(const node& n, const bool negate) + { + const node::uid_type n_uid = cnot(n.uid().as_ptr(), negate); + const node::pointer_type n_low = cnot(n.low(), negate); + const node::pointer_type n_high = cnot(n.high(), negate); + + return { n_uid, n_low, n_high }; + } + /* =========================================== LEVELS ========================================= */ inline node shift_replace(const node& n, const node::signed_label_type levels) diff --git a/test/adiar/internal/data_types/test_node.cpp b/test/adiar/internal/data_types/test_node.cpp index 6a6b84dff..09058ccb8 100644 --- a/test/adiar/internal/data_types/test_node.cpp +++ b/test/adiar/internal/data_types/test_node.cpp @@ -371,6 +371,56 @@ go_bandit([]() { it("negates 'true' terminal node", [&]() { AssertThat(!node(true), Is().EqualTo(node(false))); }); }); + + describe("cnot(const node&, bool)", [&]() { + it("leaves node_ptr children as-is if flag is not set", [&]() { + const node n = node(2u, 2u, ptr_uint64(42, 3), ptr_uint64(8, 2)); + + AssertThat(cnot(n, false), Is().EqualTo(n)); + }); + + it("leaves terminal_ptr child as-is if flag is not set", [&]() { + const node n = node(2u, 2u, terminal_F, ptr_uint64(8, 2)); + + AssertThat(cnot(n, false), Is().EqualTo(node(2, 2, terminal_F, ptr_uint64(8, 2)))); + }); + + it("leaves terminal_ptr children as-is if flag is not set", [&]() { + const node n = node(2u, 2u, terminal_F, flag(terminal_T)); + + AssertThat(cnot(n, false), Is().EqualTo(node(2, 2, terminal_F, flag(terminal_T)))); + }); + + it("leaves 'false' terminal node as-is if flag is not set", + [&]() { AssertThat(cnot(node(false), false), Is().EqualTo(node(false))); }); + + it("negates 'true' terminal node as-is if flag is not set", + [&]() { AssertThat(cnot(node(true), false), Is().EqualTo(node(true))); }); + + it("leaves node_ptr children unchanged if flag is set", [&]() { + const node n = node(2u, 2u, ptr_uint64(42, 3), ptr_uint64(8, 2)); + + AssertThat(cnot(n, true), Is().EqualTo(n)); + }); + + it("negates terminal_ptr child if flag is set", [&]() { + const node n = node(2u, 2u, terminal_F, ptr_uint64(8, 2)); + + AssertThat(cnot(n, true), Is().EqualTo(node(2, 2, terminal_T, ptr_uint64(8, 2)))); + }); + + it("negates terminal_ptr children while preserving flags if flag is set", [&]() { + const node n = node(2u, 2u, terminal_F, flag(terminal_T)); + + AssertThat(cnot(n, true), Is().EqualTo(node(2, 2, terminal_T, flag(terminal_F)))); + }); + + it("negates 'false' terminal node if flag is set", + [&]() { AssertThat(cnot(node(false), true), Is().EqualTo(node(true))); }); + + it("negates 'true' terminal node if flag is set", + [&]() { AssertThat(cnot(node(true), true), Is().EqualTo(node(false))); }); + }); }); describe("shift_replace(const node&, ...)", [&]() { From af26f390074924a15ee6218cb4f982f71e37eeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 09:46:15 +0200 Subject: [PATCH 29/30] Extend 'file_stream<>' documentation comments to 100 --- src/adiar/internal/io/file_stream.h | 116 ++++++++++++++-------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/adiar/internal/io/file_stream.h b/src/adiar/internal/io/file_stream.h index 7bf08edb1..4d790e00c 100644 --- a/src/adiar/internal/io/file_stream.h +++ b/src/adiar/internal/io/file_stream.h @@ -10,24 +10,24 @@ namespace adiar::internal { - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Stream to a file with a one-way reading direction. /// /// \tparam T The type of the file's elements /// /// \tparam Reverse Whether the reading direction should be reversed - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////////////////// template class file_stream { public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Type of the file's elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// using value_type = T; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// static size_t memory_usage() { @@ -35,71 +35,70 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// - /// \brief Buffer of a single element, since TPIE does not support a - /// `peek_back` function yet (TPIE Issue #187). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Buffer of a single element, since TPIE does not support a `peek_back` function yet + /// (TPIE Issue #187). + //////////////////////////////////////////////////////////////////////////////////////////////// mutable value_type _peeked; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether an \em unpulled element is stored in `_peeked`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// mutable bool _has_peeked = false; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether elements should be \em negated on-the-fly. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool _negate = false; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief TPIE's file stream object to read the file with. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// mutable typename tpie::file_stream _stream; - //////////////////////////////////////////////////////////////////////////// - /// \brief If attached to a shared file then hook into the reference - /// counting such that the file is not garbage collected while we - /// read from it. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief If attached to a shared file then hook into the reference counting such that the file + /// is not garbage collected while we read from it. + //////////////////////////////////////////////////////////////////////////////////////////////// shared_ptr _file_ptr; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct unattached to any file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_stream() {} - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_stream(const file_stream&) = delete; file_stream(file_stream&&) = delete; - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given shared `file`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_stream(const file& f, bool negate = false) { attach(f, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given shared `file`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// file_stream(const adiar::shared_ptr>& f, bool negate = false) { attach(f, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detaches and cleans up when destructed. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// ~file_stream() { detach(); } protected: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const file& f, const adiar::shared_ptr& shared_ptr, bool negate) { @@ -109,8 +108,8 @@ namespace adiar::internal // Hook into reference counting. _file_ptr = shared_ptr; - // Touch the file to make sure it exists on disk. Since 'f' is const, use - // the private '__touch()' member function instead. + // Touch the file to make sure it exists on disk. Since 'f' is const, use the private + // '__touch()' member function instead. f.__touch(); // Open the stream to the file @@ -121,46 +120,46 @@ namespace adiar::internal _negate = negate; } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// // Befriend the few places that need direct access to the above 'attach'. template friend class levelized_file_stream; public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a file. /// /// \pre No `file_writer` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const file& f, bool negate = false) { attach(f, nullptr, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Attach to a shared file. /// /// \pre No `file_writer` is currently attached to this file. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void attach(const adiar::shared_ptr>& f, bool negate = false) { attach(*f, f, negate); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the reader is currently attached. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool attached() const { return _stream.is_open(); } - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Detach from the file, i.e. close the stream. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// void detach() { @@ -168,10 +167,9 @@ namespace adiar::internal if (_file_ptr) { _file_ptr.reset(); } } - //////////////////////////////////////////////////////////////////////////// - /// \brief Reset the read head back to the beginning (relatively to the - /// reading direction). - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Reset the read head back to the beginning (relatively to the reading direction). + //////////////////////////////////////////////////////////////////////////////////////////////// void reset() { @@ -183,7 +181,7 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool __can_read() const { @@ -195,9 +193,9 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether the stream contains more elements. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// bool can_pull() const { @@ -205,7 +203,7 @@ namespace adiar::internal } private: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const value_type __read() { @@ -219,11 +217,11 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the next element (and move the read head). /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const value_type pull() { @@ -236,11 +234,11 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Obtain the next element (but do not move the read head) /// /// \pre `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// const value_type peek() { @@ -253,21 +251,19 @@ namespace adiar::internal } public: - //////////////////////////////////////////////////////////////////////////// - /// \brief Obtain the next element that is greater than or equal to the - /// given target value. + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Obtain the next element that is greater than or equal to the given target value. /// /// \param s The value to seek for /// /// \pre The content is in ascending order and `can_pull() == true`. - //////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////////////// template const value_type seek(seek_t tgt) { - // Notice, the peek() also changes the state of '_peeked' and - // '_has_peeked'. This initializes the invariant for 'seek' that '_peeked' - // is the "current position". + // Notice, the peek() also changes the state of '_peeked' and '_has_peeked'. This initializes + // the invariant for 'seek' that '_peeked' is the "current position". if (tgt < peek()) { return _peeked; } // Only move to "next value", if there is more to pull. From e01d502792a312ffbf8927f2deac6167b3a93a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffan=20S=C3=B8lvsten?= Date: Fri, 21 Jun 2024 10:04:18 +0200 Subject: [PATCH 30/30] Move on-the-fly negation into 'node_stream' and 'node_random_access' This is the only place it is used, and there is no need to add the additional instructions to every other instance --- src/adiar/internal/io/arc_stream.h | 24 +++++++------- src/adiar/internal/io/file_stream.h | 32 +++++++------------ src/adiar/internal/io/levelized_file_stream.h | 21 ++++++------ .../internal/io/node_arc_random_access.h | 6 ++-- src/adiar/internal/io/node_arc_stream.h | 29 +++++++++++------ src/adiar/internal/io/node_stream.h | 20 ++++++++---- test/adiar/internal/io/test_arc_file.cpp | 8 +++++ 7 files changed, 78 insertions(+), 62 deletions(-) diff --git a/src/adiar/internal/io/arc_stream.h b/src/adiar/internal/io/arc_stream.h index 317e40338..d8eebbeb6 100644 --- a/src/adiar/internal/io/arc_stream.h +++ b/src/adiar/internal/io/arc_stream.h @@ -52,17 +52,17 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////// /// \brief Construct a stream attached to an arc file. //////////////////////////////////////////////////////////////////////////// - arc_stream(const levelized_file& file, bool negate = false) + arc_stream(const levelized_file& file) { - attach(file, negate); + attach(file); } //////////////////////////////////////////////////////////////////////////// /// \brief Construct a stream unattached to a shared arc file. //////////////////////////////////////////////////////////////////////////// - arc_stream(const shared_ptr>& file, bool negate = false) + arc_stream(const shared_ptr>& file) { - attach(file, negate); + attach(file); } //////////////////////////////////////////////////////////////////////////// @@ -77,12 +77,12 @@ namespace adiar::internal /// \pre No `levelized_file_writer` is currently attached to this file. //////////////////////////////////////////////////////////////////////////// void - attach(const levelized_file& f, const bool negate = false) + attach(const levelized_file& f) { // adiar_assert(f.semi_transposed); - parent_t::attach(f, negate); - _unread_terminals[negate ^ false] = f.number_of_terminals[false]; - _unread_terminals[negate ^ true] = f.number_of_terminals[true]; + parent_t::attach(f); + _unread_terminals[false] = f.number_of_terminals[false]; + _unread_terminals[true] = f.number_of_terminals[true]; } //////////////////////////////////////////////////////////////////////////// @@ -91,12 +91,12 @@ namespace adiar::internal /// \pre No `levelized_file_writer` is currently attached to this file. //////////////////////////////////////////////////////////////////////////// void - attach(const shared_ptr>& f, const bool negate = false) + attach(const shared_ptr>& f) { // adiar_assert(f->semi_transposed); - parent_t::attach(f, negate); - _unread_terminals[negate ^ false] = f->number_of_terminals[false]; - _unread_terminals[negate ^ true] = f->number_of_terminals[true]; + parent_t::attach(f); + _unread_terminals[false] = f->number_of_terminals[false]; + _unread_terminals[true] = f->number_of_terminals[true]; } public: diff --git a/src/adiar/internal/io/file_stream.h b/src/adiar/internal/io/file_stream.h index 4d790e00c..e8aa5e923 100644 --- a/src/adiar/internal/io/file_stream.h +++ b/src/adiar/internal/io/file_stream.h @@ -46,11 +46,6 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// mutable bool _has_peeked = false; - //////////////////////////////////////////////////////////////////////////////////////////////// - /// \brief Whether elements should be \em negated on-the-fly. - //////////////////////////////////////////////////////////////////////////////////////////////// - bool _negate = false; - //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief TPIE's file stream object to read the file with. //////////////////////////////////////////////////////////////////////////////////////////////// @@ -76,17 +71,17 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given shared `file`. //////////////////////////////////////////////////////////////////////////////////////////////// - file_stream(const file& f, bool negate = false) + file_stream(const file& f) { - attach(f, negate); + attach(f); } //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Construct attached to a given shared `file`. //////////////////////////////////////////////////////////////////////////////////////////////// - file_stream(const adiar::shared_ptr>& f, bool negate = false) + file_stream(const adiar::shared_ptr>& f) { - attach(f, negate); + attach(f); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -100,7 +95,7 @@ namespace adiar::internal protected: //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(const file& f, const adiar::shared_ptr& shared_ptr, bool negate) + attach(const file& f, const adiar::shared_ptr& shared_ptr) { // Detach from prior file, if any. if (attached()) { detach(); } @@ -115,9 +110,6 @@ namespace adiar::internal // Open the stream to the file _stream.open(f._tpie_file, file::read_access); reset(); - - // Store negation flag. - _negate = negate; } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -132,9 +124,9 @@ namespace adiar::internal /// \pre No `file_writer` is currently attached to this file. //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(const file& f, bool negate = false) + attach(const file& f) { - attach(f, nullptr, negate); + attach(f, nullptr); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -143,9 +135,9 @@ namespace adiar::internal /// \pre No `file_writer` is currently attached to this file. //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(const adiar::shared_ptr>& f, bool negate = false) + attach(const adiar::shared_ptr>& f) { - attach(*f, f, negate); + attach(*f, f); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -207,13 +199,11 @@ namespace adiar::internal const value_type __read() { - value_type v; if constexpr (Reverse) { - v = _stream.read_back(); + return _stream.read_back(); } else { - v = _stream.read(); + return _stream.read(); } - return _negate ? !v : v; } public: diff --git a/src/adiar/internal/io/levelized_file_stream.h b/src/adiar/internal/io/levelized_file_stream.h index 327722af3..974d3460c 100644 --- a/src/adiar/internal/io/levelized_file_stream.h +++ b/src/adiar/internal/io/levelized_file_stream.h @@ -59,18 +59,17 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a levelized file. //////////////////////////////////////////////////////////////////////////////////////////////// - levelized_file_stream(const levelized_file& lf, const bool negate = false) + levelized_file_stream(const levelized_file& lf) { - attach(lf, negate); + attach(lf); } //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared levelized file. //////////////////////////////////////////////////////////////////////////////////////////////// - levelized_file_stream(const shared_ptr>& lf, - const bool negate = false) + levelized_file_stream(const shared_ptr>& lf) { - attach(lf, negate); + attach(lf); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -85,12 +84,12 @@ namespace adiar::internal /// \pre No `levelized_file_writer` is currently attached to this file. //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(const levelized_file& f, const bool negate = false) + attach(const levelized_file& f) { if (!f.exists()) f.__touch(); for (size_t s_idx = 0; s_idx < streams; s_idx++) - _streams[s_idx].attach(f._files[s_idx], nullptr, negate); + _streams[s_idx].attach(f._files[s_idx], nullptr); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -99,12 +98,12 @@ namespace adiar::internal /// \pre No `levelized_file_writer` is currently attached to this file. //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(const shared_ptr>& f, const bool negate = false) + attach(const shared_ptr>& f) { if (!f->exists()) f->touch(); for (size_t s_idx = 0; s_idx < streams; s_idx++) - _streams[s_idx].attach(f->_files[s_idx], f, negate); + _streams[s_idx].attach(f->_files[s_idx], f); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -262,7 +261,7 @@ namespace adiar::internal attach(const levelized_file& lf) { if (!lf.exists()) lf.__touch(); - parent_type::attach(lf._level_info_file, nullptr, false); + parent_type::attach(lf._level_info_file, nullptr); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -273,7 +272,7 @@ namespace adiar::internal attach(const adiar::shared_ptr>& lf) { if (!lf->exists()) lf->touch(); - parent_type::attach(lf->_level_info_file, lf, false); + parent_type::attach(lf->_level_info_file, lf); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/io/node_arc_random_access.h b/src/adiar/internal/io/node_arc_random_access.h index 91ad756a9..f1989a199 100644 --- a/src/adiar/internal/io/node_arc_random_access.h +++ b/src/adiar/internal/io/node_arc_random_access.h @@ -38,6 +38,7 @@ namespace adiar::internal : parent_type(f, negate) { // adiar_assert(f.indexable); + adiar_assert(negate == false); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -49,6 +50,7 @@ namespace adiar::internal : parent_type(f, negate) { // adiar_assert(f->indexable); + adiar_assert(negate == false); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -58,9 +60,7 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// node_arc_random_access(const __dd& diagram) : node_arc_random_access(diagram.template get<__dd::shared_arc_file_type>(), diagram._negate) - { - // adiar_assert(diagram->indexable); - } + {} public: //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/io/node_arc_stream.h b/src/adiar/internal/io/node_arc_stream.h index d7f7d8a13..dae9a06bb 100644 --- a/src/adiar/internal/io/node_arc_stream.h +++ b/src/adiar/internal/io/node_arc_stream.h @@ -26,13 +26,19 @@ namespace adiar::internal using value_type = node; private: + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Arc-based input to-be converted into nodes on-the-fly. + //////////////////////////////////////////////////////////////////////////////////////////////// arc_stream _stream; + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Whether a converted node has been buffered. + //////////////////////////////////////////////////////////////////////////////////////////////// bool _has_peeked = false; + //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Latest converted node. + //////////////////////////////////////////////////////////////////////////////////////////////// node _peeked; public: @@ -63,19 +69,23 @@ namespace adiar::internal //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to an arc file. //////////////////////////////////////////////////////////////////////////////////////////////// - node_arc_stream(levelized_file& file, const bool negate = false) + node_arc_stream(levelized_file& file, + [[maybe_unused]] const bool negate = false) : _stream(/*need to sort before attach*/) { - attach(file, negate); + adiar_assert(negate == false); + attach(file); } //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared arc file. //////////////////////////////////////////////////////////////////////////////////////////////// - node_arc_stream(const shared_ptr>& file, const bool negate = false) + node_arc_stream(const shared_ptr>& file, + [[maybe_unused]] const bool negate = false) : _stream(/*need to sort before attach*/) { - attach(file, negate); + adiar_assert(negate == false); + attach(file); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -87,7 +97,8 @@ namespace adiar::internal : _stream(/*need to sort before attach*/) { adiar_assert(diagram.template has<__dd::shared_arc_file_type>()); - attach(diagram.template get<__dd::shared_arc_file_type>(), diagram._negate); + adiar_assert(diagram._negate == false); + attach(diagram.template get<__dd::shared_arc_file_type>()); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -96,13 +107,13 @@ namespace adiar::internal /// \remark This sorts the internal arcs of the file. //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(levelized_file& file, const bool negate = false) + attach(levelized_file& file) { if (file.semi_transposed) { file.sort(idx__internal); file.semi_transposed = false; } - _stream.attach(file, negate); + _stream.attach(file); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -111,13 +122,13 @@ namespace adiar::internal /// \remark This sorts the internal arcs of the file. //////////////////////////////////////////////////////////////////////////////////////////////// void - attach(const shared_ptr>& file, const bool negate = false) + attach(const shared_ptr>& file) { if (file->semi_transposed) { file->sort(idx__internal); file->semi_transposed = false; } - _stream.attach(file, negate); + _stream.attach(file); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/adiar/internal/io/node_stream.h b/src/adiar/internal/io/node_stream.h index 44bb0e931..7dcdee5d6 100644 --- a/src/adiar/internal/io/node_stream.h +++ b/src/adiar/internal/io/node_stream.h @@ -23,6 +23,11 @@ namespace adiar::internal { using parent_type = levelized_file_stream; + //////////////////////////////////////////////////////////////////////////////////////////////// + /// \brief Whether nodes should be \em negated on-the-fly. + //////////////////////////////////////////////////////////////////////////////////////////////// + bool _negate = false; + public: //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create unattached to any file. @@ -37,21 +42,24 @@ namespace adiar::internal /// \brief Create attached to a node file. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const levelized_file& file, bool negate = false) - : parent_type(file, negate) + : parent_type(file) + , _negate(negate) {} //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a shared node file. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const shared_ptr>& file, bool negate = false) - : parent_type(file, negate) + : parent_type(file) + , _negate(negate) {} //////////////////////////////////////////////////////////////////////////////////////////////// /// \brief Create attached to a Decision Diagram. //////////////////////////////////////////////////////////////////////////////////////////////// node_stream(const dd& diagram) - : parent_type(diagram.file_ptr(), diagram.is_negated()) + : parent_type(diagram.file_ptr()) + , _negate(diagram.is_negated()) {} //////////////////////////////////////////////////////////////////////////////////////////////// @@ -71,7 +79,7 @@ namespace adiar::internal const node pull() { - return parent_type::template pull<0>(); + return cnot(parent_type::template pull<0>(), this->_negate); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -82,7 +90,7 @@ namespace adiar::internal const node peek() { - return parent_type::template peek<0>(); + return cnot(parent_type::template peek<0>(), this->_negate); } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -95,7 +103,7 @@ namespace adiar::internal const node seek(const node::uid_type& u) { - return parent_type::_streams[0].seek(u); + return cnot(parent_type::_streams[0].seek(u), this->_negate); } }; } diff --git a/test/adiar/internal/io/test_arc_file.cpp b/test/adiar/internal/io/test_arc_file.cpp index 273c83291..768ca6b19 100644 --- a/test/adiar/internal/io/test_arc_file.cpp +++ b/test/adiar/internal/io/test_arc_file.cpp @@ -239,6 +239,7 @@ go_bandit([]() { AssertThat(as.can_pull_terminal(), Is().False()); }); + /* it("merges terminal arcs on 'pull' [negated]", [&af]() { arc_stream<> as(af, true); @@ -259,6 +260,7 @@ go_bandit([]() { Is().EqualTo(arc(arc::pointer_type(1, 0), true, arc::pointer_type(false)))); AssertThat(as.can_pull_terminal(), Is().False()); }); + */ it("reads internal arcs as given [non-default: forwards]", [&af]() { arc_stream<> as(af); @@ -318,6 +320,7 @@ go_bandit([]() { AssertThat(as.unread_terminals(true), Is().EqualTo(0u)); }); + /* it("provides number of unread terminals [negate=true]", [&af]() { arc_stream<> as(af, true); @@ -360,6 +363,7 @@ go_bandit([]() { AssertThat(as.unread_terminals(false), Is().EqualTo(0u)); AssertThat(as.unread_terminals(true), Is().EqualTo(0u)); }); + */ }); describe("arc_writer + node_arc_stream", []() { @@ -460,6 +464,7 @@ go_bandit([]() { AssertThat(ns.can_pull(), Is().True()); }); + /* it("can read single-node BDD [negated]", [&]() { node_arc_stream ns(x0_ordered, true); @@ -469,6 +474,7 @@ go_bandit([]() { AssertThat(ns.can_pull(), Is().False()); }); + */ it("can pull after peek of single-node BDD", [&]() { node_arc_stream ns(x0_ordered); @@ -746,6 +752,7 @@ go_bandit([]() { AssertThat(ns.can_pull(), Is().False()); }); + /* it("can pull larger BDD [negated + reverse]", [&]() { AssertThat(large_untransposed2.semi_transposed, Is().False()); @@ -773,6 +780,7 @@ go_bandit([]() { AssertThat(ns.can_pull(), Is().False()); }); + */ }); describe("arc_writer + node_arc_random_access", []() {