From cd9decb15634bdf94a51cd8f11b82be464bd35bb Mon Sep 17 00:00:00 2001 From: Mathias Soeken Date: Tue, 17 Mar 2020 17:00:40 +0100 Subject: [PATCH 1/3] (Re-)add test cases for Akers. --- test/algorithms/akers_synthesis.cpp | 284 +++++++++++++++++++++++++++ test/algorithms/cut_rewriting.cpp | 22 +++ test/algorithms/node_resynthesis.cpp | 32 +++ test/algorithms/quality.cpp | 28 +++ test/algorithms/refactoring.cpp | 22 +++ 5 files changed, 388 insertions(+) create mode 100644 test/algorithms/akers_synthesis.cpp diff --git a/test/algorithms/akers_synthesis.cpp b/test/algorithms/akers_synthesis.cpp new file mode 100644 index 000000000..7077f0dc1 --- /dev/null +++ b/test/algorithms/akers_synthesis.cpp @@ -0,0 +1,284 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace mockturtle; + +TEST_CASE( "Check Akers for MAJ-3", "[akers_synthesis]" ) +{ + std::vector xs{5, kitty::dynamic_truth_table( 3 )}; + + create_majority( xs[0] ); + for ( auto i = 0u; i < unsigned( xs[0].num_bits() ); i++ ) + { + set_bit( xs[1], i ); + } + + auto mig = akers_synthesis( xs[0], xs[1] ); + + kitty::create_nth_var( xs[2], 0 ); + kitty::create_nth_var( xs[3], 1 ); + kitty::create_nth_var( xs[4], 2 ); + + CHECK( mig.compute( mig.index_to_node( mig.size() - 1 ), xs.begin() + 2, xs.end() ) == xs[0] ); + CHECK( mig.size() == 5 ); +} + +TEST_CASE( "Check Akers for MAJ-5", "[akers_synthesis]" ) +{ + std::vector xs{7, kitty::dynamic_truth_table( 5 )}; + + create_majority( xs[0] ); + for ( auto i = 0u; i < unsigned( xs[0].num_bits() ); i++ ) + { + set_bit( xs[1], i ); + } + + auto mig = akers_synthesis( xs[0], xs[1] ); + + kitty::create_nth_var( xs[2], 0 ); + kitty::create_nth_var( xs[3], 1 ); + kitty::create_nth_var( xs[4], 2 ); + kitty::create_nth_var( xs[5], 3 ); + kitty::create_nth_var( xs[6], 4 ); + + mig.foreach_gate( [&]( auto n ) { + std::vector fanin{3, kitty::dynamic_truth_table( 5 )}; + mig.foreach_fanin( n, [&]( auto s, auto j ) { + fanin[j] = xs[mig.node_to_index( mig.get_node( s ) ) + 1]; + } ); + xs.push_back( mig.compute( n, fanin.begin(), fanin.end() ) ); + } ); + CHECK( xs[xs.size() - 1] == xs[0] ); +} + +TEST_CASE( "Check Akers for MAJ-5 in XMG", "[akers_synthesis]" ) +{ + std::vector xs{7, kitty::dynamic_truth_table( 5 )}; + + create_majority( xs[0] ); + for ( auto i = 0u; i < unsigned( xs[0].num_bits() ); i++ ) + { + set_bit( xs[1], i ); + } + + auto xmg = akers_synthesis( xs[0], xs[1] ); + + kitty::create_nth_var( xs[2], 0 ); + kitty::create_nth_var( xs[3], 1 ); + kitty::create_nth_var( xs[4], 2 ); + kitty::create_nth_var( xs[5], 3 ); + kitty::create_nth_var( xs[6], 4 ); + + xmg.foreach_gate( [&]( auto n ) { + std::vector fanin{3, kitty::dynamic_truth_table( 5 )}; + xmg.foreach_fanin( n, [&]( auto s, auto j ) { + fanin[j] = xs[xmg.node_to_index( xmg.get_node( s ) ) + 1]; + } ); + xs.push_back( xmg.compute( n, fanin.begin(), fanin.end() ) ); + } ); + CHECK( xs[xs.size() - 1] == xs[0] ); +} + +TEST_CASE( "Check Akers for random - 4 inputs", "[akers_synthesis]" ) +{ + for ( auto y = 0; y < 5; y++ ) + { + std::vector xs{6, kitty::dynamic_truth_table( 4 )}; + kitty::create_nth_var( xs[2], 0 ); + kitty::create_nth_var( xs[3], 1 ); + kitty::create_nth_var( xs[4], 2 ); + kitty::create_nth_var( xs[5], 3 ); + + create_random( xs[0] ); + + for ( auto i = 0u; i < unsigned( xs[0].num_bits() ); i++ ) + { + set_bit( xs[1], i ); + } + + auto mig = akers_synthesis( xs[0], xs[1] ); + if ( mig.size() > 4 ) + { + mig.foreach_gate( [&]( auto n ) { + std::vector fanin{3, kitty::dynamic_truth_table( 4 )}; + mig.foreach_fanin( n, [&]( auto s, auto j ) { + if ( mig.node_to_index( mig.get_node( s ) ) == 0 ) + { + fanin[j] = ~xs[1]; + } + else + { + fanin[j] = xs[mig.node_to_index( mig.get_node( s ) ) + 1]; + } + } ); + xs.push_back( mig.compute( n, fanin.begin(), fanin.end() ) ); + } ); + + mig.foreach_po( [&]( auto n ) { + if ( mig.is_complemented( n ) ) + CHECK( ~xs[xs.size() - 1] == xs[0] ); + else + CHECK( xs[xs.size() - 1] == xs[0] ); + } ); + } + } +} + +TEST_CASE( "Check Akers for random - 5 inputs", "[akers_synthesis]" ) +{ + for ( auto y = 0; y < 5; y++ ) + { + std::vector xs{7, kitty::dynamic_truth_table( 5 )}; + kitty::create_nth_var( xs[2], 0 ); + kitty::create_nth_var( xs[3], 1 ); + kitty::create_nth_var( xs[4], 2 ); + kitty::create_nth_var( xs[5], 3 ); + kitty::create_nth_var( xs[6], 4 ); + + create_random( xs[0] ); + + for ( auto i = 0u; i < unsigned( xs[0].num_bits() ); i++ ) + { + set_bit( xs[1], i ); + } + + auto mig = akers_synthesis( xs[0], xs[1] ); + if ( mig.size() > 6 ) + { + mig.foreach_gate( [&]( auto n ) { + std::vector fanin{3, kitty::dynamic_truth_table( 5 )}; + mig.foreach_fanin( n, [&]( auto s, auto j ) { + if ( mig.node_to_index( mig.get_node( s ) ) == 0 ) + { + fanin[j] = ~xs[1]; + } + else + { + fanin[j] = xs[mig.node_to_index( mig.get_node( s ) ) + 1]; + } + } ); + xs.push_back( mig.compute( n, fanin.begin(), fanin.end() ) ); + } ); + + mig.foreach_po( [&]( auto n ) { + if ( mig.is_complemented( n ) ) + CHECK( ~xs[xs.size() - 1] == xs[0] ); + else + CHECK( xs[xs.size() - 1] == xs[0] ); + } ); + } + } +} + +TEST_CASE( "Check Akers for random - 6 inputs", "[akers_synthesis]" ) +{ + for ( auto y = 0; y < 1; y++ ) + { + std::vector xs{8, kitty::dynamic_truth_table( 6 )}; + kitty::create_nth_var( xs[2], 0 ); + kitty::create_nth_var( xs[3], 1 ); + kitty::create_nth_var( xs[4], 2 ); + kitty::create_nth_var( xs[5], 3 ); + kitty::create_nth_var( xs[6], 4 ); + kitty::create_nth_var( xs[7], 5 ); + + create_random( xs[0] ); + + for ( auto i = 0u; i < unsigned( xs[0].num_bits() ); i++ ) + { + set_bit( xs[1], i ); + } + + auto mig = akers_synthesis( xs[0], xs[1] ); + if ( mig.size() > 6 ) + { + mig.foreach_gate( [&]( auto n ) { + std::vector fanin{3, kitty::dynamic_truth_table( 6 )}; + mig.foreach_fanin( n, [&]( auto s, auto j ) { + if ( mig.node_to_index( mig.get_node( s ) ) == 0 ) + { + fanin[j] = ~xs[1]; + } + else + { + fanin[j] = xs[mig.node_to_index( mig.get_node( s ) ) + 1]; + } + } ); + xs.push_back( mig.compute( n, fanin.begin(), fanin.end() ) ); + } ); + mig.foreach_po( [&]( auto n ) { + if ( mig.is_complemented( n ) ) + CHECK( ~xs[xs.size() - 1] == xs[0] ); + else + CHECK( xs[xs.size() - 1] == xs[0] ); + } ); + } + } +} + +TEST_CASE( "Check leaves iterator -- easy case ", "[akers_synthesis]" ) +{ + mig_network mig; + auto a = mig.create_pi(); + auto b = mig.create_pi(); + auto c = mig.create_pi(); + auto d = mig.create_pi(); + + std::vector operations; + operations.push_back( mig.create_and( a, b ) ); + operations.push_back( mig.create_and( c, d ) ); + + std::vector xs_in{2, kitty::dynamic_truth_table( 2 )}; + std::vector xs{5, kitty::dynamic_truth_table( 4 )}; + create_from_binary_string( xs_in[0], "0110" ); + for ( auto i = 0u; i < unsigned( xs_in[0].num_bits() ); i++ ) + { + set_bit( xs_in[1], i ); + } + auto t = akers_synthesis( mig, xs_in[0], xs_in[1], operations.begin(), operations.end() ); + mig.create_po( t ); + + kitty::create_nth_var( xs[1], 0 ); + kitty::create_nth_var( xs[2], 1 ); + kitty::create_nth_var( xs[3], 2 ); + kitty::create_nth_var( xs[4], 3 ); + + for ( auto i = 0u; i < unsigned( xs[1].num_bits() ); i++ ) + { + set_bit( xs[0], i ); + } + + CHECK( mig.num_gates() == 5 ); + + if ( mig.size() > 6 ) + { + mig.foreach_gate( [&]( auto n ) { + std::vector fanin{3, kitty::dynamic_truth_table( 4 )}; + mig.foreach_fanin( n, [&]( auto s, auto j ) { + if ( mig.node_to_index( mig.get_node( s ) ) == 0 ) + { + fanin[j] = ~xs[0]; + } + else + { + fanin[j] = xs[mig.get_node( s )]; + } + } ); + xs.push_back( mig.compute( n, fanin.begin(), fanin.end() ) ); + } ); + mig.foreach_po( [&]( auto n ) { + if ( mig.is_complemented( n ) ) + CHECK( ~xs[xs.size() - 1] == binary_xor( binary_and( xs[1], xs[2] ), binary_and( xs[4], xs[3] ) ) ); + else + CHECK( xs[xs.size() - 1] == binary_xor( binary_and( xs[1], xs[2] ), binary_and( xs[4], xs[3] ) ) ); + } ); + } +} diff --git a/test/algorithms/cut_rewriting.cpp b/test/algorithms/cut_rewriting.cpp index 387100637..ba3d76ab9 100644 --- a/test/algorithms/cut_rewriting.cpp +++ b/test/algorithms/cut_rewriting.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,27 @@ TEST_CASE("Cut rewriting with XMG3 4-input npn database", "[cut_rewriting]") CHECK( xmg.num_gates() == 1 ); } +TEST_CASE( "Cut rewriting with Akers synthesis", "[cut_rewriting]" ) +{ + mig_network mig; + const auto a = mig.create_pi(); + const auto b = mig.create_pi(); + const auto c = mig.create_pi(); + + const auto f = mig.create_maj( a, mig.create_maj( a, b, c ), c ); + mig.create_po( f ); + + akers_resynthesis resyn; + cut_rewriting( mig, resyn ); + + mig = cleanup_dangling( mig ); + + CHECK( mig.size() == 5 ); + CHECK( mig.num_pis() == 3 ); + CHECK( mig.num_pos() == 1 ); + CHECK( mig.num_gates() == 1 ); +} + TEST_CASE( "Cut rewriting from constant", "[cut_rewriting]" ) { mig_network mig; diff --git a/test/algorithms/node_resynthesis.cpp b/test/algorithms/node_resynthesis.cpp index f1bdd6bcf..5490893de 100644 --- a/test/algorithms/node_resynthesis.cpp +++ b/test/algorithms/node_resynthesis.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -193,6 +194,37 @@ TEST_CASE( "Node resynthesis with optimum networks", "[node_resynthesis]" ) } ); } +TEST_CASE( "Node resynthesis with Akers resynthesis", "[node_resynthesis]" ) +{ + kitty::dynamic_truth_table maj( 3 ); + kitty::create_majority( maj ); + + klut_network klut; + const auto a = klut.create_pi(); + const auto b = klut.create_pi(); + const auto c = klut.create_pi(); + const auto f = klut.create_node( {a, b, c}, maj ); + klut.create_po( f ); + + akers_resynthesis resyn; + const auto mig = node_resynthesis( klut, resyn ); + + CHECK( mig.size() == 5 ); + CHECK( mig.num_pis() == 3 ); + CHECK( mig.num_pos() == 1 ); + CHECK( mig.num_gates() == 1 ); + + mig.foreach_po( [&]( auto const& f ) { + CHECK( !mig.is_complemented( f ) ); + } ); + + mig.foreach_node( [&]( auto n ) { + mig.foreach_fanin( n, [&]( auto const& f ) { + CHECK( !mig.is_complemented( f ) ); + } ); + } ); +} + TEST_CASE( "Node resynthesis from constant", "[node_resynthesis]" ) { klut_network klut; diff --git a/test/algorithms/quality.cpp b/test/algorithms/quality.cpp index 931399593..888f568d1 100644 --- a/test/algorithms/quality.cpp +++ b/test/algorithms/quality.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -136,6 +137,33 @@ TEST_CASE( "Test quality improvement of cut rewriting with NPN4 resynthesis", "[ CHECK( v2 == std::vector{{0, 20, 78, 49, 158, 79, 196, 132, 525, 2, 255}} ); } +TEST_CASE( "Test quality improvement of MIG refactoring with Akers resynthesis", "[quality]" ) +{ + // without zero gain + const auto v = foreach_benchmark( []( auto& ntk, auto ) { + const auto before = ntk.num_gates(); + akers_resynthesis resyn; + refactoring( ntk, resyn ); + ntk = cleanup_dangling( ntk ); + return before - ntk.num_gates(); + } ); + + CHECK( v == std::vector{{0, 18, 34, 22, 114, 56, 253, 113, 442, 449, 69}} ); + + // with zero gain + const auto v2 = foreach_benchmark( []( auto& ntk, auto ) { + const auto before = ntk.num_gates(); + akers_resynthesis resyn; + refactoring_params ps; + ps.allow_zero_gain = true; + refactoring( ntk, resyn, ps ); + ntk = cleanup_dangling( ntk ); + return before - ntk.num_gates(); + } ); + + CHECK( v2 == std::vector{{0, 18, 34, 21, 115, 55, 254, 118, 443, 449, 66}} ); +} + TEST_CASE( "Test quality of MIG algebraic depth rewriting", "[quality]" ) { const auto v = foreach_benchmark( []( auto& ntk, auto ) { diff --git a/test/algorithms/refactoring.cpp b/test/algorithms/refactoring.cpp index e27a4a855..e71cc12c0 100644 --- a/test/algorithms/refactoring.cpp +++ b/test/algorithms/refactoring.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,27 @@ TEST_CASE( "Refactoring of bad MAJ", "[refactoring]" ) CHECK( mig.num_gates() == 1 ); } +TEST_CASE( "Refactoring with Akers synthesis", "[refactoring]" ) +{ + mig_network mig; + const auto a = mig.create_pi(); + const auto b = mig.create_pi(); + const auto c = mig.create_pi(); + + const auto f = mig.create_maj( a, mig.create_maj( a, b, c ), c ); + mig.create_po( f ); + + akers_resynthesis resyn; + refactoring( mig, resyn ); + + mig = cleanup_dangling( mig ); + + CHECK( mig.size() == 5 ); + CHECK( mig.num_pis() == 3 ); + CHECK( mig.num_pos() == 1 ); + CHECK( mig.num_gates() == 1 ); +} + namespace detail { template From 3762f4a452ff8ea0c28f787d89b77f564d814a41 Mon Sep 17 00:00:00 2001 From: Eleonora Date: Thu, 9 Apr 2020 17:54:15 +0200 Subject: [PATCH 2/3] fix eq cec of quality test (akers) --- .../mockturtle/algorithms/akers_synthesis.hpp | 29 +++++++++++++++++++ test/algorithms/quality.cpp | 9 +++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/include/mockturtle/algorithms/akers_synthesis.hpp b/include/mockturtle/algorithms/akers_synthesis.hpp index a8e1ed622..ab5854218 100644 --- a/include/mockturtle/algorithms/akers_synthesis.hpp +++ b/include/mockturtle/algorithms/akers_synthesis.hpp @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -634,6 +635,9 @@ class akers_synthesis_impl table.reduce(); } + if ( ntk.node_to_index( ntk.get_node( c_to_f[last_gate_id] ) ) == 0 ) + return ntk.get_constant( 0 ^ ntk.is_complemented( c_to_f[last_gate_id] ) ); + return c_to_f[last_gate_id]; } @@ -807,6 +811,31 @@ signal akers_synthesis( Ntk& ntk, kitty::dynamic_truth_table const& func, k assert( func.num_vars() == care.num_vars() ); assert( std::distance( begin, end ) == func.num_vars() ); + auto pi = begin; + + if ( is_const0( func ) ) + return ntk.get_constant( 0 ); + auto tt_1 = func; + unary_not( tt_1 ); + if ( is_const0( tt_1 ) ) + return ntk.get_constant( 1 ); + + tt_1 = func; + for ( auto i = 0; i < func.num_vars(); i++ ) + { + create_nth_var( tt_1, i ); + auto it = *pi++; + if ( tt_1 == func ) + { + return it; + } + unary_not( tt_1 ); + if ( tt_1 == func ) + { + return !it; + } + } + detail::akers_synthesis_impl tt( ntk, func, care, begin, end ); return tt.run(); } diff --git a/test/algorithms/quality.cpp b/test/algorithms/quality.cpp index 888f568d1..d53d2376d 100644 --- a/test/algorithms/quality.cpp +++ b/test/algorithms/quality.cpp @@ -21,15 +21,14 @@ #include #include #include -#include -#include #include #include #include +#include #include -#include #include #include +#include #include #include @@ -148,7 +147,7 @@ TEST_CASE( "Test quality improvement of MIG refactoring with Akers resynthesis", return before - ntk.num_gates(); } ); - CHECK( v == std::vector{{0, 18, 34, 22, 114, 56, 253, 113, 442, 449, 69}} ); + CHECK( v == std::vector{{0, 18, 34, 22, 114, 56, 153, 107, 432, 449, 69}} ); // with zero gain const auto v2 = foreach_benchmark( []( auto& ntk, auto ) { @@ -161,7 +160,7 @@ TEST_CASE( "Test quality improvement of MIG refactoring with Akers resynthesis", return before - ntk.num_gates(); } ); - CHECK( v2 == std::vector{{0, 18, 34, 21, 115, 55, 254, 118, 443, 449, 66}} ); + CHECK( v2 == std::vector{{0, 18, 34, 21, 115, 55, 139, 107, 409, 449, 66}} ); } TEST_CASE( "Test quality of MIG algebraic depth rewriting", "[quality]" ) From b0c1182ab718fdcfd7447d7831acbb0383e31479 Mon Sep 17 00:00:00 2001 From: Eleonora Date: Sat, 11 Apr 2020 16:13:39 +0200 Subject: [PATCH 3/3] akers and cut rewriting --- test/algorithms/cut_rewriting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/algorithms/cut_rewriting.cpp b/test/algorithms/cut_rewriting.cpp index e28f44169..2ac43ea88 100644 --- a/test/algorithms/cut_rewriting.cpp +++ b/test/algorithms/cut_rewriting.cpp @@ -71,7 +71,7 @@ TEST_CASE( "Cut rewriting with Akers synthesis", "[cut_rewriting]" ) mig.create_po( f ); akers_resynthesis resyn; - cut_rewriting( mig, resyn ); + cut_rewriting_with_compatibility_graph( mig, resyn ); mig = cleanup_dangling( mig );