Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BDD/RelPrev/Renaming (Preliminary Work) #676

Merged
merged 30 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e0d178e
Add missing '_' prefix to '__dd' and 'dd' class member variables and …
SSoelvsten Jun 17, 2024
724d802
Use public member functions rather than being friends of 'dd' class
SSoelvsten Jun 18, 2024
80658fc
Add 'shift_replace' for 'ptr_uint64'
SSoelvsten Jun 18, 2024
710ca6a
Add 'shift_replace' for 'node'
SSoelvsten Jun 18, 2024
fda5b93
Debug 'level_info' and add 'shift_replace(...)'
SSoelvsten Jun 18, 2024
cb5f599
Fix incorrect name of type in 'level_info_stream' according to style …
SSoelvsten Jun 18, 2024
33ee67c
Update 'level_info_stream' to code style
SSoelvsten Jun 18, 2024
448037d
Add missing unit tests for 'level_info_stream'
SSoelvsten Jun 18, 2024
c06456a
Fix incorrect type name according to style guide
SSoelvsten Jun 18, 2024
f7ad53a
Add missing tests and remove duplicated inputs for tests for 'node_st…
SSoelvsten Jun 18, 2024
fdf41b4
Add TODO for better responsibility/performance
SSoelvsten Jun 18, 2024
8503ad8
Fill and Extend comments in <adiar/internal/io/...>
SSoelvsten Jun 18, 2024
511856f
Extend comments in <adiar/internal/dd_func.h> to column 100
SSoelvsten Jun 18, 2024
f038049
Clean-up of code to auto-detect 'replace_type'
SSoelvsten Jun 18, 2024
4a65c22
Swap order of member functions
SSoelvsten Jun 18, 2024
7946159
Clean up 'level_merger' and add missing unit tests
SSoelvsten Jun 18, 2024
c85d24a
Clean up interface of 'comparison_check'
SSoelvsten Jun 18, 2024
6493fa5
Clean up tests for 'bdd_apply'
SSoelvsten Jun 18, 2024
075ca23
Clean up of 'bdd_ite' implementation
SSoelvsten Jun 19, 2024
141db3b
Fix conversion of negated BDD terminal into ZDD throws exception
SSoelvsten Jun 19, 2024
5121d15
Fix descriptions for convert algorithm groups
SSoelvsten Jun 19, 2024
d345743
Add missing unit tests for on-the-fly negation
SSoelvsten Jun 20, 2024
db4c306
Keep Assembler output for 'playground' target to investigate low-leve…
SSoelvsten Jun 21, 2024
88819d4
Make 'shift_replace(const ptr_uint64&)' branchless (Thanks, Lasse!)
SSoelvsten Jun 20, 2024
7899929
Move befriending of 'essential(...)' into a more reasonable place
SSoelvsten Jun 21, 2024
5f30f5a
Add 'cnot(const ptr_uint64&, bool)' for a more branch-less on-the-fly…
SSoelvsten Jun 21, 2024
33b4147
Clean up in tests for 'node' class
SSoelvsten Jun 21, 2024
7cda4ec
Add 'cnot(const node&, bool)' for more branch-less on-the-fly negation
SSoelvsten Jun 21, 2024
af26f39
Extend 'file_stream<>' documentation comments to 100
SSoelvsten Jun 21, 2024
e01d502
Move on-the-fly negation into 'node_stream' and 'node_random_access'
SSoelvsten Jun 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
4 changes: 2 additions & 2 deletions src/adiar/bdd/bdd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
348 changes: 173 additions & 175 deletions src/adiar/bdd/if_then_else.cpp

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/adiar/bdd/negate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
6 changes: 3 additions & 3 deletions src/adiar/internal/algorithms/convert.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/adiar/internal/algorithms/nested_sweeping.h
Original file line number Diff line number Diff line change
Expand Up @@ -2095,13 +2095,13 @@ namespace adiar::internal
// Is it a terminal?
if (input.template has<shared_node_file_type>()
&& input.template get<shared_node_file_type>()->is_terminal()) {
return reduced_t(input.template get<shared_node_file_type>(), input.negate);
return reduced_t(input.template get<shared_node_file_type>(), input._negate);
}

// Otherwise obtain the semi-transposed DAG (construct it if necessary)
const shared_arc_file_type dag = input.template has<shared_arc_file_type>()
? input.template get<shared_arc_file_type>()
: transpose(reduced_t(input.template get<shared_node_file_type>(), input.negate));
: transpose(reduced_t(input.template get<shared_node_file_type>(), input._negate));

// Compute amount of memory available for auxiliary data structures after having opened all
// streams.
Expand Down
132 changes: 56 additions & 76 deletions src/adiar/internal/algorithms/pred.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <bool tv>
class input_bound_levels
{
Expand All @@ -28,17 +27,15 @@ namespace adiar::internal

public:
static size_t
pq1_upper_bound(const shared_levelized_file<node>& in_1,
const shared_levelized_file<node>& 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<node>& in_1,
const shared_levelized_file<node>& 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
Expand All @@ -48,9 +45,8 @@ namespace adiar::internal
}

public:
input_bound_levels(const shared_levelized_file<node>& f0,
const shared_levelized_file<node>& /*f1*/)
: in_meta_1(f0)
input_bound_levels(const dd& a, const dd& /*b*/)
: in_meta_1(a)
{}

void
Expand All @@ -74,14 +70,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 dd_policy>
class isomorphism_policy
Expand Down Expand Up @@ -155,36 +151,33 @@ 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<node> 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<node> 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_file<node>s are 'canonical'.
/// (3) The negation flags given to both shared_levelized_file<node>s agree
/// (breaks canonicity)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
bool
fast_isomorphism_check(const shared_levelized_file<node>& f0,
const shared_levelized_file<node>& 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
Expand All @@ -194,67 +187,62 @@ namespace adiar::internal
return true;
}

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
bool
is_isomorphic(const exec_policy& ep,
const shared_levelized_file<node>& f0,
const shared_levelized_file<node>& 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()) {
// Are they trivially not the same, since they have different number of nodes?
if (a->size() != b->size()) {
#ifdef ADIAR_STATS
stats_equality.exit_on_nodecount += 1u;
#endif
return false;
}

// 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
return false;
}

// 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]) {
// Are they trivially not the same, since they have different number of terminal arcs?
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
return false;
}

// Are they trivially not the same, since they have different number of
// levels?
if (f0->levels() != f1->levels()) {
// Are they trivially not the same, since they have different number of levels?
if (a->levels() != b->levels()) {
#ifdef ADIAR_STATS
stats_equality.exit_on_varcount += 1u;
#endif
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);
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
Expand All @@ -263,28 +251,20 @@ 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.
if (f0->is_canonical() && f1->is_canonical() && negate0 == negate1) {
// Compare their content to discern whether there exists an isomorphism between them.
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<isomorphism_policy>(ep, f0, f1, negate0, negate1);
return comparison_check<isomorphism_policy>(ep, a, b);
}
}

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);
}
}
Loading
Loading