Skip to content

Commit

Permalink
Add compile-time 'xnor_op' to expose code-pruning to the compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
SSoelvsten committed Mar 5, 2024
1 parent fdbfaa6 commit 2f3942c
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/adiar/bdd/apply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ namespace adiar
__bdd
bdd_xnor(const exec_policy& ep, const bdd& f, const bdd& g)
{
return bdd_apply(ep, f, g, xnor_op);
apply_prod2_policy<internal::xnor_op> policy;
return internal::prod2(ep, f, g, policy);
}

__bdd
Expand Down Expand Up @@ -259,7 +260,8 @@ namespace adiar
__bdd
bdd_equiv(const exec_policy& ep, const bdd& f, const bdd& g)
{
return bdd_apply(ep, f, g, equiv_op);
apply_prod2_policy<internal::equiv_op> policy;
return internal::prod2(ep, f, g, policy);
}

__bdd
Expand Down
70 changes: 70 additions & 0 deletions src/adiar/internal/bool_op.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,76 @@ namespace adiar::internal
return is_negating(p.value());
}
};

//////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Alternative for `binary_op` hardcoded for a logical 'xnor'.
///
/// \details The benefit of this over `binary_op` is to skip pre-computations and to expose
/// optimisations and simplifications to the compiler.
//////////////////////////////////////////////////////////////////////////////////////////////////
class xnor_op
: public commutative_op<xnor_op>
{
////////////////////////////////////////////////////////////////////////////////////////////////
public:
bool
operator ()(const bool lhs, const bool rhs) const
{
return !(lhs ^ rhs);
}

template<typename Pointer>
Pointer
operator ()(const Pointer& lhs, const Pointer& rhs) const
{
return !(lhs ^ rhs);
}

////////////////////////////////////////////////////////////////////////////////////////////////
protected:
friend commutative_op<xnor_op>;

template<typename T>
static constexpr bool
can_shortcut(const T&/*t*/)
{
return false;
}

static constexpr bool
is_idempotent(const bool p)
{
return p;
}

template<typename Pointer>
static bool
is_idempotent(const Pointer& p)
{
return is_idempotent(p.value());
}

static constexpr bool
is_negating(const bool p)
{
return !p;
}

template<typename Pointer>
static constexpr bool
is_negating(const Pointer& p)
{
return is_negating(p.value());
}
};

//////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief Alternative for `binary_op` hardcoded for a logical 'equiv'.
///
/// \details The benefit of this over `binary_op` is to skip pre-computations and to expose
/// optimisations and simplifications to the compiler.
//////////////////////////////////////////////////////////////////////////////////////////////////
using equiv_op = xnor_op;
}

#endif // ADIAR_INTERNAL_BOOL_OP_H
79 changes: 79 additions & 0 deletions test/adiar/internal/test_bool_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ go_bandit([]() {
AssertThat(can_right_shortcut(adiar::xor_op, true), Is().False());
});

it("is correct for 'adiar::xnor_op'", []() {
AssertThat(can_left_shortcut(adiar::xnor_op, false), Is().False());
AssertThat(can_left_shortcut(adiar::xnor_op, true), Is().False());

AssertThat(can_right_shortcut(adiar::xnor_op, false), Is().False());
AssertThat(can_right_shortcut(adiar::xnor_op, true), Is().False());
});

it("is correct for 'adiar::imp_op'", []() {
AssertThat(can_left_shortcut(adiar::imp_op, false), Is().True());
AssertThat(can_left_shortcut(adiar::imp_op, true), Is().False());
Expand Down Expand Up @@ -104,6 +112,14 @@ go_bandit([]() {
AssertThat(is_right_idempotent(adiar::xor_op, true), Is().False());
});

it("is correct for 'adiar::xnor_op'", []() {
AssertThat(is_left_idempotent(adiar::xnor_op, false), Is().False());
AssertThat(is_left_idempotent(adiar::xnor_op, true), Is().True());

AssertThat(is_right_idempotent(adiar::xnor_op, false), Is().False());
AssertThat(is_right_idempotent(adiar::xnor_op, true), Is().True());
});

it("is correct for 'adiar::imp_op'", []() {
AssertThat(is_left_idempotent(adiar::imp_op, false), Is().False());
AssertThat(is_left_idempotent(adiar::imp_op, true), Is().True());
Expand Down Expand Up @@ -162,6 +178,14 @@ go_bandit([]() {
AssertThat(is_right_negating(adiar::xor_op, true), Is().True());
});

it("is correct for 'adiar::xnor_op'", []() {
AssertThat(is_left_negating(adiar::xnor_op, false), Is().True());
AssertThat(is_left_negating(adiar::xnor_op, true), Is().False());

AssertThat(is_right_negating(adiar::xnor_op, false), Is().True());
AssertThat(is_right_negating(adiar::xnor_op, true), Is().False());
});

it("is correct for 'adiar::imp_op'", []() {
AssertThat(is_left_negating(adiar::imp_op, false), Is().False());
AssertThat(is_left_negating(adiar::imp_op, true), Is().False());
Expand Down Expand Up @@ -894,5 +918,60 @@ go_bandit([]() {
AssertThat(op.is_commutative(), Is().True());
});
});

describe("xnor_op, equiv_op", []() {
const adiar::internal::xnor_op op;

constexpr ptr_uint64 ptr_false(false);
constexpr ptr_uint64 ptr_true(true);

it("operator() (const bool, const bool)", [&]() {
AssertThat(op(false, false), Is().EqualTo(true));
AssertThat(op(false, true), Is().EqualTo(false));
AssertThat(op(true, false), Is().EqualTo(false));
AssertThat(op(true, true), Is().EqualTo(true));
});

it("operator() (const Pointer&, const Pointer&)", [&]() {
AssertThat(op(ptr_false, ptr_false), Is().EqualTo(ptr_true));
AssertThat(op(ptr_false, ptr_true), Is().EqualTo(ptr_false));
AssertThat(op(ptr_true, ptr_false), Is().EqualTo(ptr_false));
AssertThat(op(ptr_true, ptr_true), Is().EqualTo(ptr_true));
});

it(".can_left_shortcut(const Pointer&)", [&]() {
AssertThat(op.can_left_shortcut(ptr_false), Is().False());
AssertThat(op.can_left_shortcut(ptr_true), Is().False());
});

it(".can_right_shortcut(const Pointer&)", [&]() {
AssertThat(op.can_right_shortcut(ptr_false), Is().False());
AssertThat(op.can_right_shortcut(ptr_true), Is().False());
});

it(".is_left_idempotent(const Pointer&)", [&]() {
AssertThat(op.is_left_idempotent(ptr_false), Is().False());
AssertThat(op.is_left_idempotent(ptr_true), Is().True());
});

it(".is_right_idempotent(const Pointer&)", [&]() {
AssertThat(op.is_right_idempotent(ptr_false), Is().False());
AssertThat(op.is_right_idempotent(ptr_true), Is().True());
});

it(".is_left_negating(const Pointer&)", [&]() {
AssertThat(op.is_left_negating(ptr_false), Is().True());
AssertThat(op.is_left_negating(ptr_true), Is().False());
});

it(".is_right_negating(const Pointer&)", [&]() {
AssertThat(op.is_right_negating(ptr_false), Is().True());
AssertThat(op.is_right_negating(ptr_true), Is().False());
});

it(".is_commutative()", [&]() {
AssertThat(op.is_commutative(), Is().True());
});
});
});
});

0 comments on commit 2f3942c

Please sign in to comment.