From 1c408b62da43efe641794794c217104bf4c0aae7 Mon Sep 17 00:00:00 2001 From: "Siang-Yun (Sonia) Lee" Date: Tue, 5 Jan 2021 22:48:02 +0100 Subject: [PATCH] Fixing missed cases in mig_resub (#415) * is_dead check is not needed * happy new year! * performance bug in exhaustive resub * fix 2-resub * clean up * use enumerative resub (the old one) by default * update experimental results --- experiments/mig_resubstitution.cpp | 2 +- experiments/mig_resubstitution.json | 219 ++---------- .../algorithms/functional_reduction.hpp | 12 +- include/mockturtle/algorithms/mig_resub.hpp | 329 +++++++++--------- .../algorithms/mig_resyn_engines.hpp | 2 +- .../mockturtle/algorithms/resubstitution.hpp | 7 +- 6 files changed, 207 insertions(+), 364 deletions(-) diff --git a/experiments/mig_resubstitution.cpp b/experiments/mig_resubstitution.cpp index 933853a4d..47e241834 100644 --- a/experiments/mig_resubstitution.cpp +++ b/experiments/mig_resubstitution.cpp @@ -1,5 +1,5 @@ /* mockturtle: C++ logic network library - * Copyright (C) 2018-2019 EPFL + * Copyright (C) 2018-2021 EPFL * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/experiments/mig_resubstitution.json b/experiments/mig_resubstitution.json index bde0ec390..7177d9444 100644 --- a/experiments/mig_resubstitution.json +++ b/experiments/mig_resubstitution.json @@ -4,289 +4,144 @@ { "benchmark": "adder", "equivalent": true, - "runtime": 0.01759999990463257, + "runtime": 0.010364412330091, "size_after": 893, "size_before": 1020 }, { "benchmark": "bar", "equivalent": true, - "runtime": 0.03628699854016304, - "size_after": 3072, + "runtime": 0.030435612425208092, + "size_after": 2944, "size_before": 3336 }, { "benchmark": "div", "equivalent": true, - "runtime": 0.9812279939651489, - "size_after": 56651, + "runtime": 1.4462156295776367, + "size_after": 51914, "size_before": 57247 }, { "benchmark": "hyp", "equivalent": true, - "runtime": 6.720967769622803, - "size_after": 206473, + "runtime": 9.733596801757813, + "size_after": 198816, "size_before": 214335 }, { "benchmark": "log2", "equivalent": true, - "runtime": 0.42284300923347473, - "size_after": 32008, + "runtime": 0.5198823809623718, + "size_after": 31998, "size_before": 32060 }, { "benchmark": "max", "equivalent": true, - "runtime": 0.023905999958515167, + "runtime": 0.023132337257266045, "size_after": 2840, "size_before": 2865 }, { "benchmark": "multiplier", "equivalent": true, - "runtime": 0.3989030122756958, - "size_after": 26819, + "runtime": 0.44245970249176025, + "size_after": 26796, "size_before": 27062 }, { "benchmark": "sin", "equivalent": true, - "runtime": 0.0933689996600151, - "size_after": 5339, + "runtime": 0.10537709295749664, + "size_after": 5317, "size_before": 5416 }, { "benchmark": "sqrt", "equivalent": true, - "runtime": 0.5849940180778503, - "size_after": 21902, + "runtime": 0.5356785655021667, + "size_after": 20410, "size_before": 24618 }, { "benchmark": "square", "equivalent": true, - "runtime": 0.3226509988307953, - "size_after": 18276, + "runtime": 0.3154604136943817, + "size_after": 18060, "size_before": 18484 }, { "benchmark": "arbiter", "equivalent": true, - "runtime": 0.10873500257730484, - "size_after": 11839, + "runtime": 0.12454893440008163, + "size_after": 11711, "size_before": 11839 }, { "benchmark": "cavlc", "equivalent": true, - "runtime": 0.07001599669456482, - "size_after": 636, + "runtime": 0.07970646768808365, + "size_after": 615, "size_before": 693 }, { "benchmark": "ctrl", "equivalent": true, - "runtime": 0.04500100016593933, - "size_after": 100, + "runtime": 0.034438855946063995, + "size_after": 86, "size_before": 174 }, { "benchmark": "dec", "equivalent": true, - "runtime": 0.01410400029271841, + "runtime": 0.01321916002780199, "size_after": 304, "size_before": 304 }, { "benchmark": "i2c", "equivalent": true, - "runtime": 0.01971299946308136, - "size_after": 1280, + "runtime": 0.019494887441396713, + "size_after": 1245, "size_before": 1342 }, { "benchmark": "int2float", "equivalent": true, - "runtime": 0.006262000184506178, - "size_after": 237, + "runtime": 0.006591695826500654, + "size_after": 222, "size_before": 260 }, { "benchmark": "mem_ctrl", "equivalent": true, - "runtime": 0.7440239787101746, - "size_after": 44612, + "runtime": 0.9023139476776123, + "size_after": 43447, "size_before": 46836 }, { "benchmark": "priority", "equivalent": true, - "runtime": 0.01584099978208542, - "size_after": 776, + "runtime": 0.010226909071207047, + "size_after": 668, "size_before": 978 }, { "benchmark": "router", "equivalent": true, - "runtime": 0.002862999914214015, + "runtime": 0.0028271928895264864, "size_after": 257, "size_before": 257 }, { "benchmark": "voter", "equivalent": true, - "runtime": 0.23970000445842743, - "size_after": 11870, + "runtime": 0.30536797642707825, + "size_after": 10462, "size_before": 13758 } ], - "version": "bbd1506" - }, - { - "entries": [ - { - "benchmark": "adder", - "equivalent": true, - "runtime": 0.010076023638248444, - "size_after": 893, - "size_before": 1020 - }, - { - "benchmark": "bar", - "equivalent": true, - "runtime": 0.03214477375149727, - "size_after": 3072, - "size_before": 3336 - }, - { - "benchmark": "div", - "equivalent": true, - "runtime": 0.67690509557724, - "size_after": 56714, - "size_before": 57247 - }, - { - "benchmark": "hyp", - "equivalent": true, - "runtime": 5.334950923919678, - "size_after": 206473, - "size_before": 214335 - }, - { - "benchmark": "log2", - "equivalent": true, - "runtime": 0.4067056477069855, - "size_after": 32008, - "size_before": 32060 - }, - { - "benchmark": "max", - "equivalent": true, - "runtime": 0.021115295588970184, - "size_after": 2840, - "size_before": 2865 - }, - { - "benchmark": "multiplier", - "equivalent": true, - "runtime": 0.4099847078323364, - "size_after": 26819, - "size_before": 27062 - }, - { - "benchmark": "sin", - "equivalent": true, - "runtime": 0.09224862605333328, - "size_after": 5339, - "size_before": 5416 - }, - { - "benchmark": "sqrt", - "equivalent": true, - "runtime": 0.45702600479125977, - "size_after": 21902, - "size_before": 24618 - }, - { - "benchmark": "square", - "equivalent": true, - "runtime": 0.27489277720451355, - "size_after": 18276, - "size_before": 18484 - }, - { - "benchmark": "arbiter", - "equivalent": true, - "runtime": 0.10679267346858978, - "size_after": 11839, - "size_before": 11839 - }, - { - "benchmark": "cavlc", - "equivalent": true, - "runtime": 0.06770826876163483, - "size_after": 636, - "size_before": 693 - }, - { - "benchmark": "ctrl", - "equivalent": true, - "runtime": 0.025390056893229485, - "size_after": 103, - "size_before": 174 - }, - { - "benchmark": "dec", - "equivalent": true, - "runtime": 0.01241659838706255, - "size_after": 304, - "size_before": 304 - }, - { - "benchmark": "i2c", - "equivalent": true, - "runtime": 0.01579423062503338, - "size_after": 1280, - "size_before": 1342 - }, - { - "benchmark": "int2float", - "equivalent": true, - "runtime": 0.005563724786043167, - "size_after": 237, - "size_before": 260 - }, - { - "benchmark": "mem_ctrl", - "equivalent": true, - "runtime": 0.7887808084487915, - "size_after": 44613, - "size_before": 46836 - }, - { - "benchmark": "priority", - "equivalent": true, - "runtime": 0.014381092973053455, - "size_after": 781, - "size_before": 978 - }, - { - "benchmark": "router", - "equivalent": true, - "runtime": 0.0028713271021842957, - "size_after": 257, - "size_before": 257 - }, - { - "benchmark": "voter", - "equivalent": true, - "runtime": 0.23080433905124664, - "size_after": 11874, - "size_before": 13758 - } - ], - "version": "88afeb8" + "version": "17b339b" } ] diff --git a/include/mockturtle/algorithms/functional_reduction.hpp b/include/mockturtle/algorithms/functional_reduction.hpp index 336da18f3..719807043 100644 --- a/include/mockturtle/algorithms/functional_reduction.hpp +++ b/include/mockturtle/algorithms/functional_reduction.hpp @@ -1,5 +1,5 @@ /* mockturtle: C++ logic network library - * Copyright (C) 2018-2020 EPFL + * Copyright (C) 2018-2021 EPFL * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -180,11 +180,6 @@ class functional_reduction_impl ntk.foreach_gate( [&]( auto const& n, auto i ) { pbar( i, i, candidates ); - if ( ntk.is_dead( n ) ) - { - return true; /* next */ - } - check_tts( n ); bool const_value; if ( tts[n] == zero ) @@ -234,11 +229,6 @@ class functional_reduction_impl ntk.foreach_gate( [&]( auto const& root, auto i ) { pbar( i, i, candidates ); - if ( ntk.is_dead( root ) ) - { - return true; /* next */ - } - check_tts( root ); auto tt = tts[root]; auto ntt = ~tts[root]; diff --git a/include/mockturtle/algorithms/mig_resub.hpp b/include/mockturtle/algorithms/mig_resub.hpp index 6c57e0130..a7d4e0f86 100644 --- a/include/mockturtle/algorithms/mig_resub.hpp +++ b/include/mockturtle/algorithms/mig_resub.hpp @@ -1,5 +1,5 @@ /* mockturtle: C++ logic network library - * Copyright (C) 2018-2019 EPFL + * Copyright (C) 2018-2021 EPFL * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -28,6 +28,7 @@ \brief Majority-specific resustitution rules \author Heinz Riener + \author Siang-Yun Lee */ #pragma once @@ -53,12 +54,12 @@ inline bool relevance( const static_truth_table& tt0, const static_trut return is_const0( ( ( tt0 ^ tt ) & ( tt1 ^ tt2 ) ) ); } -} +} /* namespace kitty */ namespace mockturtle { -struct mig_resub_stats +struct mig_enumerative_resub_stats { /*! \brief Accumulated runtime for const-resub */ stopwatch<>::duration time_resubC{0}; @@ -81,9 +82,6 @@ struct mig_resub_stats /*! \brief Accumulated runtime for two-resub. */ stopwatch<>::duration time_resub2{0}; - /*! \brief Accumulated runtime for three-resub. */ - stopwatch<>::duration time_resub3{0}; - /*! \brief Number of accepted constant resubsitutions */ uint32_t num_const_accepts{0}; @@ -96,25 +94,19 @@ struct mig_resub_stats /*! \brief Number of accepted relevance resubsitutions */ uint32_t num_divR_accepts{0}; - /*! \brief Number of accepted single AND-resubsitutions */ - uint64_t num_div1_and_accepts{0}; - - /*! \brief Number of accepted single OR-resubsitutions */ - uint64_t num_div1_or_accepts{0}; - /*! \brief Number of accepted two resubsitutions */ uint64_t num_div2_accepts{0}; void report() const { - std::cout << "[i] kernel: mig_resub_functor\n"; + std::cout << "[i] kernel: mig_enumerative_resub_functor\n"; std::cout << fmt::format( "[i] constant-resub {:6d} ({:>5.2f} secs)\n", num_const_accepts, to_seconds( time_resubC ) ); std::cout << fmt::format( "[i] 0-resub {:6d} ({:>5.2f} secs)\n", num_div0_accepts, to_seconds( time_resub0 ) ); - std::cout << fmt::format( "[i] collect unate divisors ({:>5.2f} secs)\n", to_seconds( time_collect_unate_divisors ) ); std::cout << fmt::format( "[i] R-resub {:6d} ({:>5.2f} secs)\n", num_divR_accepts, to_seconds( time_resubR ) ); + std::cout << fmt::format( "[i] collect unate divisors ({:>5.2f} secs)\n", to_seconds( time_collect_unate_divisors ) ); std::cout << fmt::format( "[i] 1-resub {:6d} = {:6d} MAJ ({:>5.2f} secs)\n", num_div1_accepts, num_div1_accepts, to_seconds( time_resub1 ) ); std::cout << fmt::format( "[i] collect binate divisors ({:>5.2f} secs)\n", to_seconds( time_collect_binate_divisors ) ); @@ -123,56 +115,46 @@ struct mig_resub_stats std::cout << fmt::format( "[i] total {:6d}\n", (num_const_accepts + num_div0_accepts + num_divR_accepts + num_div1_accepts + num_div2_accepts) ); } -}; /* mig_resub_stats */ +}; /* mig_enumerative_resub_stats */ -template -struct mig_resub_functor +template +struct mig_enumerative_resub_functor { public: using node = mig_network::node; using signal = mig_network::signal; - using stats = mig_resub_stats; + using stats = mig_enumerative_resub_stats; struct unate_divisors { - std::vector positive_divisors0; - std::vector positive_divisors1; - std::vector negative_divisors0; - std::vector negative_divisors1; + std::vector u0; + std::vector u1; std::vector next_candidates; void clear() { - positive_divisors0.clear(); - positive_divisors1.clear(); - negative_divisors0.clear(); - negative_divisors1.clear(); + u0.clear(); + u1.clear(); next_candidates.clear(); } }; struct binate_divisors { - std::vector positive_divisors0; - std::vector positive_divisors1; - std::vector positive_divisors2; - std::vector negative_divisors0; - std::vector negative_divisors1; - std::vector negative_divisors2; + std::vector b0; + std::vector b1; + std::vector b2; void clear() { - positive_divisors0.clear(); - positive_divisors1.clear(); - positive_divisors2.clear(); - negative_divisors0.clear(); - negative_divisors1.clear(); - negative_divisors2.clear(); + b0.clear(); + b1.clear(); + b2.clear(); } }; public: - explicit mig_resub_functor( Ntk& ntk, Simulator const& sim, std::vector const& divs, uint32_t num_divs, stats& st ) + explicit mig_enumerative_resub_functor( Ntk& ntk, Simulator const& sim, std::vector const& divs, uint32_t num_divs, stats& st ) : ntk( ntk ) , sim( sim ) , divs( divs ) @@ -373,33 +355,40 @@ struct mig_resub_functor udivs.clear(); auto const& tt = sim.get_tt( ntk.make_signal( root ) ); + auto const& one = sim.get_tt( ntk.get_constant( true ) ); for ( auto i = 0u; i < num_divs; ++i ) { auto const d0 = divs.at( i ); if ( ntk.level( d0 ) > required - 1 ) continue; + auto const& tt_s0 = sim.get_tt( ntk.make_signal( d0 ) ); for ( auto j = i + 1; j < num_divs; ++j ) { auto const d1 = divs.at( j ); if ( ntk.level( d1 ) > required - 1 ) continue; - - auto const& tt_s0 = sim.get_tt( ntk.make_signal( d0 ) ); auto const& tt_s1 = sim.get_tt( ntk.make_signal( d1 ) ); /* Boolean filtering rule for MAJ-3 */ if ( kitty::ternary_majority( tt_s0, tt_s1, tt ) == tt ) { - udivs.positive_divisors0.emplace_back( ntk.make_signal( d0 ) ); - udivs.positive_divisors1.emplace_back( ntk.make_signal( d1 ) ); + udivs.u0.emplace_back( ntk.make_signal( d0 ) ); + udivs.u1.emplace_back( ntk.make_signal( d1 ) ); continue; } if ( kitty::ternary_majority( ~tt_s0, tt_s1, tt ) == tt ) { - udivs.negative_divisors0.emplace_back( ntk.make_signal( d0 ) ); - udivs.negative_divisors1.emplace_back( ntk.make_signal( d1 ) ); + udivs.u0.emplace_back( !ntk.make_signal( d0 ) ); + udivs.u1.emplace_back( ntk.make_signal( d1 ) ); + continue; + } + + if ( kitty::ternary_majority( tt_s0, ~tt_s1, tt ) == tt ) + { + udivs.u0.emplace_back( ntk.make_signal( d0 ) ); + udivs.u1.emplace_back( !ntk.make_signal( d1 ) ); continue; } @@ -407,9 +396,38 @@ struct mig_resub_functor udivs.next_candidates.emplace_back( ntk.make_signal( d1 ) ); } + if constexpr ( use_constant ) /* allowing "not real" MAJ gates (one fanin is constant) */ + { + if ( kitty::ternary_majority( tt_s0, one, tt ) == tt ) + { + udivs.u0.emplace_back( ntk.make_signal( d0 ) ); + udivs.u1.emplace_back( ntk.get_constant( true ) ); + continue; + } + + if ( kitty::ternary_majority( ~tt_s0, one, tt ) == tt ) + { + udivs.u0.emplace_back( !ntk.make_signal( d0 ) ); + udivs.u1.emplace_back( ntk.get_constant( true ) ); + continue; + } + + if ( kitty::ternary_majority( tt_s0, ~one, tt ) == tt ) + { + udivs.u0.emplace_back( ntk.make_signal( d0 ) ); + udivs.u1.emplace_back( ntk.get_constant( false ) ); + continue; + } + } + if ( std::find( udivs.next_candidates.begin(), udivs.next_candidates.end(), ntk.make_signal( d0 ) ) == udivs.next_candidates.end() ) udivs.next_candidates.emplace_back( ntk.make_signal( d0 ) ); } + + if constexpr ( use_constant ) + { + udivs.next_candidates.emplace_back( ntk.get_constant( true ) ); + } } std::optional resub_div1( node const& root, uint32_t required ) @@ -417,35 +435,31 @@ struct mig_resub_functor (void)required; auto const& tt = sim.get_tt( ntk.make_signal( root ) ); - /* check for positive unate divisors */ - for ( auto i = 0u; i < udivs.positive_divisors0.size(); ++i ) + for ( auto i = 0u; i < udivs.u0.size(); ++i ) { - auto const s0 = udivs.positive_divisors0.at( i ); - auto const s1 = udivs.positive_divisors1.at( i ); + auto const s0 = udivs.u0.at( i ); + auto const s1 = udivs.u1.at( i ); + auto const& tt_s0 = sim.get_tt( s0 ); + auto const& tt_s1 = sim.get_tt( s1 ); - for ( auto j = i + 1; j < udivs.positive_divisors0.size(); ++j ) + for ( auto j = i + 1; j < udivs.u0.size(); ++j ) { - auto s2 = udivs.positive_divisors0.at( j ); - - auto const& tt_s0 = sim.get_tt( s0 ); - auto const& tt_s1 = sim.get_tt( s1 ); + auto s2 = udivs.u0.at( j ); auto tt_s2 = sim.get_tt( s2 ); if ( kitty::ternary_majority( tt_s0, tt_s1, tt_s2 ) == tt ) { - // ++st.num_div1_maj_accepts; auto const a = sim.get_phase( ntk.get_node( s0 ) ) ? !s0 : s0; auto const b = sim.get_phase( ntk.get_node( s1 ) ) ? !s1 : s1; auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s2 : s2; return sim.get_phase( root ) ? !ntk.create_maj( a, b, c ) : ntk.create_maj( a, b, c ); } - s2 = udivs.positive_divisors1.at( j ); + s2 = udivs.u1.at( j ); tt_s2 = sim.get_tt( s2 ); if ( kitty::ternary_majority( tt_s0, tt_s1, tt_s2 ) == tt ) { - // ++st.num_div1_maj_accepts; auto const a = sim.get_phase( ntk.get_node( s0 ) ) ? !s0 : s0; auto const b = sim.get_phase( ntk.get_node( s1 ) ) ? !s1 : s1; auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s2 : s2; @@ -454,43 +468,6 @@ struct mig_resub_functor } } - /* check for negative unate divisors */ - for ( auto i = 0u; i < udivs.negative_divisors0.size(); ++i ) - { - auto const s0 = udivs.negative_divisors0.at( i ); - auto const s1 = udivs.negative_divisors1.at( i ); - - for ( auto j = i + 1; j < udivs.negative_divisors0.size(); ++j ) - { - auto s2 = udivs.negative_divisors0.at( j ); - - auto const& tt_s0 = sim.get_tt( s0 ); - auto const& tt_s1 = sim.get_tt( s1 ); - auto tt_s2 = sim.get_tt( s2 ); - - if ( kitty::ternary_majority( ~tt_s0, tt_s1, tt_s2 ) == tt ) - { - // ++st.num_div1_maj_accepts; - auto const a = sim.get_phase( ntk.get_node( s0 ) ) ? !s0 : s0; - auto const b = sim.get_phase( ntk.get_node( s1 ) ) ? !s1 : s1; - auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s2 : s2; - return sim.get_phase( root ) ? !ntk.create_maj( !a, b, c ) : ntk.create_maj( !a, b, c ); - } - - s2 = udivs.negative_divisors1.at( j ); - tt_s2 = sim.get_tt( s2 ); - - if ( kitty::ternary_majority( ~tt_s0, tt_s1, tt_s2 ) == tt ) - { - // ++st.num_div1_maj_accepts; - auto const a = sim.get_phase( ntk.get_node( s0 ) ) ? !s0 : s0; - auto const b = sim.get_phase( ntk.get_node( s1 ) ) ? !s1 : s1; - auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s2 : s2; - return sim.get_phase( root ) ? !ntk.create_maj( !a, b, c ) : ntk.create_maj( !a, b, c ); - } - } - } - return std::nullopt; } @@ -523,35 +500,68 @@ struct mig_resub_functor auto const& tt_s2 = sim.get_tt( s2 ); + /* Note: the implication relation is actually not necessary for majority; this is an over-filtering */ if ( kitty::implies( kitty::ternary_majority( tt_s0, tt_s1, tt_s2 ), tt ) ) { - bdivs.positive_divisors0.emplace_back( s0 ); - bdivs.positive_divisors1.emplace_back( s1 ); - bdivs.positive_divisors2.emplace_back( s2 ); + bdivs.b0.emplace_back( s0 ); + bdivs.b1.emplace_back( s1 ); + bdivs.b2.emplace_back( s2 ); continue; } if ( kitty::implies( kitty::ternary_majority( ~tt_s0, tt_s1, tt_s2 ), tt ) ) { - bdivs.positive_divisors0.emplace_back( !s0 ); - bdivs.positive_divisors1.emplace_back( s1 ); - bdivs.positive_divisors2.emplace_back( s2 ); + bdivs.b0.emplace_back( !s0 ); + bdivs.b1.emplace_back( s1 ); + bdivs.b2.emplace_back( s2 ); + continue; + } + + if ( kitty::implies( kitty::ternary_majority( tt_s0, ~tt_s1, tt_s2 ), tt ) ) + { + bdivs.b0.emplace_back( s0 ); + bdivs.b1.emplace_back( !s1 ); + bdivs.b2.emplace_back( s2 ); + continue; + } + + if ( kitty::implies( kitty::ternary_majority( tt_s0, tt_s1, ~tt_s2 ), tt ) ) + { + bdivs.b0.emplace_back( s0 ); + bdivs.b1.emplace_back( s1 ); + bdivs.b2.emplace_back( !s2 ); continue; } - if ( kitty::implies( tt, kitty::ternary_majority( tt_s0, tt_s1, tt_s2 ) ) ) + if ( kitty::implies( kitty::ternary_majority( ~tt_s0, ~tt_s1, tt_s2 ), tt ) ) { - bdivs.negative_divisors0.emplace_back( s0 ); - bdivs.negative_divisors1.emplace_back( s1 ); - bdivs.negative_divisors2.emplace_back( s2 ); + bdivs.b0.emplace_back( !s0 ); + bdivs.b1.emplace_back( !s1 ); + bdivs.b2.emplace_back( s2 ); continue; } - if ( kitty::implies( tt, kitty::ternary_majority( ~tt_s0, tt_s1, tt_s2 ) ) ) + if ( kitty::implies( kitty::ternary_majority( tt_s0, ~tt_s1, ~tt_s2 ), tt ) ) { - bdivs.negative_divisors0.emplace_back( !s0 ); - bdivs.negative_divisors1.emplace_back( s1 ); - bdivs.negative_divisors2.emplace_back( s2 ); + bdivs.b0.emplace_back( s0 ); + bdivs.b1.emplace_back( !s1 ); + bdivs.b2.emplace_back( !s2 ); + continue; + } + + if ( kitty::implies( kitty::ternary_majority( ~tt_s0, tt_s1, ~tt_s2 ), tt ) ) + { + bdivs.b0.emplace_back( !s0 ); + bdivs.b1.emplace_back( s1 ); + bdivs.b2.emplace_back( !s2 ); + continue; + } + + if ( kitty::implies( kitty::ternary_majority( ~tt_s0, ~tt_s1, ~tt_s2 ), tt ) ) + { + bdivs.b0.emplace_back( !s0 ); + bdivs.b1.emplace_back( !s1 ); + bdivs.b2.emplace_back( !s2 ); continue; } } @@ -562,59 +572,24 @@ struct mig_resub_functor std::optional resub_div2( node const& root, uint32_t required ) { (void)required; - auto const s = ntk.make_signal( root ); - auto const& tt = sim.get_tt( s ); - - /* check positive unate divisors */ - for ( auto i = 0u; i < udivs.positive_divisors0.size(); ++i ) - { - auto const& s0 = udivs.positive_divisors0.at( i ); - auto const& s1 = udivs.positive_divisors1.at( i ); - - for ( auto j = 0u; j < bdivs.positive_divisors0.size(); ++j ) - { - auto const& s2 = bdivs.positive_divisors0.at( j ); - auto const& s3 = bdivs.positive_divisors1.at( j ); - auto const& s4 = bdivs.positive_divisors2.at( j ); - - auto const a = sim.get_phase( ntk.get_node( s0 ) ) ? !s0 : s0; - auto const b = sim.get_phase( ntk.get_node( s1 ) ) ? !s1 : s1; - auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s1 : s2; - auto const d = sim.get_phase( ntk.get_node( s3 ) ) ? !s2 : s3; - auto const e = sim.get_phase( ntk.get_node( s4 ) ) ? !s3 : s4; - - auto const& tt_s0 = sim.get_tt( s0 ); - auto const& tt_s1 = sim.get_tt( s1 ); - auto const& tt_s2 = sim.get_tt( s2 ); - auto const& tt_s3 = sim.get_tt( s3 ); - auto const& tt_s4 = sim.get_tt( s4 ); - - if ( kitty::ternary_majority( kitty::ternary_majority( tt_s0, tt_s1, tt_s2 ), tt_s3, tt_s4 ) == tt ) - { - return sim.get_phase( root ) ? - !ntk.create_maj( a, b, ntk.create_maj( c, d, e ) ) : - ntk.create_maj( a, b, ntk.create_maj( c, d, e ) ); - } - } - } + auto const& tt = sim.get_tt( ntk.make_signal( root ) ); - /* check negative unate divisors */ - for ( auto i = 0u; i < udivs.negative_divisors0.size(); ++i ) + for ( auto i = 0u; i < udivs.u0.size(); ++i ) { - auto const& s0 = udivs.negative_divisors0.at( i ); - auto const& s1 = udivs.negative_divisors1.at( i ); + auto const& s0 = udivs.u0.at( i ); + auto const& s1 = udivs.u1.at( i ); - for ( auto j = 0u; j < bdivs.negative_divisors0.size(); ++j ) + for ( auto j = 0u; j < bdivs.b0.size(); ++j ) { - auto const& s2 = bdivs.negative_divisors0.at( j ); - auto const& s3 = bdivs.negative_divisors1.at( j ); - auto const& s4 = bdivs.negative_divisors2.at( j ); + auto const& s2 = bdivs.b0.at( j ); + auto const& s3 = bdivs.b1.at( j ); + auto const& s4 = bdivs.b2.at( j ); auto const a = sim.get_phase( ntk.get_node( s0 ) ) ? !s0 : s0; auto const b = sim.get_phase( ntk.get_node( s1 ) ) ? !s1 : s1; - auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s1 : s2; - auto const d = sim.get_phase( ntk.get_node( s3 ) ) ? !s2 : s3; - auto const e = sim.get_phase( ntk.get_node( s4 ) ) ? !s3 : s4; + auto const c = sim.get_phase( ntk.get_node( s2 ) ) ? !s2 : s2; + auto const d = sim.get_phase( ntk.get_node( s3 ) ) ? !s3 : s3; + auto const e = sim.get_phase( ntk.get_node( s4 ) ) ? !s4 : s4; auto const& tt_s0 = sim.get_tt( s0 ); auto const& tt_s1 = sim.get_tt( s1 ); @@ -622,7 +597,7 @@ struct mig_resub_functor auto const& tt_s3 = sim.get_tt( s3 ); auto const& tt_s4 = sim.get_tt( s4 ); - if ( kitty::ternary_majority( ~kitty::ternary_majority( tt_s0, tt_s1, tt_s2 ), tt_s3, tt_s4 ) == tt ) + if ( kitty::ternary_majority( tt_s0, tt_s1, kitty::ternary_majority( tt_s2, tt_s3, tt_s4 ) ) == tt ) { return sim.get_phase( root ) ? !ntk.create_maj( a, b, ntk.create_maj( c, d, e ) ) : @@ -643,18 +618,40 @@ struct mig_resub_functor unate_divisors udivs; binate_divisors bdivs; -}; /* mig_resub_functor */ +}; /* mig_enumerative_resub_functor */ + +struct mig_resyn_stats +{ + /*! \brief Time for finding dependency function. */ + stopwatch<>::duration time_compute_function{0}; + + /*! \brief Number of found solutions. */ + uint32_t num_success{0}; + + /*! \brief Number of times that no solution can be found. */ + uint32_t num_fail{0}; + + void report() const + { + // clang-format off + std::cout << "[i] \n"; + std::cout << fmt::format( "[i] #solution = {:6d}\n", num_success ); + std::cout << fmt::format( "[i] #invoke = {:6d}\n", num_success + num_fail ); + std::cout << fmt::format( "[i] engine time: {:>5.2f} secs\n", to_seconds( time_compute_function ) ); + // clang-format on + } +}; /* mig_resyn_stats */ template> -struct mig_resub_functor_new +struct mig_resyn_functor { public: using node = mig_network::node; using signal = mig_network::signal; - using stats = mig_resub_stats; + using stats = mig_resyn_stats; public: - explicit mig_resub_functor_new( Ntk& ntk, Simulator const& sim, std::vector const& divs, uint32_t num_divs, stats& st ) + explicit mig_resyn_functor( Ntk& ntk, Simulator const& sim, std::vector const& divs, uint32_t num_divs, stats& st ) : ntk( ntk ) , sim( sim ) , tts( ntk ) @@ -678,9 +675,12 @@ struct mig_resub_functor_new } engine.add_divisors( divs.begin(), divs.end(), tts ); - auto const res = engine.compute_function( std::min( potential_gain - 1, max_inserts ) ); + auto const res = call_with_stopwatch( st.time_compute_function, [&]() { + return engine.compute_function( std::min( potential_gain - 1, max_inserts ) ); + }); if ( res ) { + ++st.num_success; signal ret; real_gain = potential_gain - (*res).num_gates(); insert( ntk, div_signals.begin(), div_signals.end(), *res, [&]( signal const& s ){ ret = s; } ); @@ -688,6 +688,7 @@ struct mig_resub_functor_new } else { + ++st.num_fail; return std::nullopt; } } @@ -699,7 +700,7 @@ struct mig_resub_functor_new std::vector const& divs; std::vector div_signals; stats& st; -}; +}; /* mig_resyn_functor */ /*! \brief MIG-specific resubstitution algorithm. * @@ -765,7 +766,8 @@ void mig_resubstitution( Ntk& ntk, resubstitution_params const& ps = {}, resubst { using truthtable_t = kitty::static_truth_table<8u>; using truthtable_dc_t = kitty::dynamic_truth_table; - using resub_impl_t = detail::resubstitution_impl, truthtable_dc_t>>>; + using functor_t = mig_enumerative_resub_functor, truthtable_dc_t>; + using resub_impl_t = detail::resubstitution_impl>; resubstitution_stats st; typename resub_impl_t::engine_st_t engine_st; @@ -790,7 +792,8 @@ void mig_resubstitution( Ntk& ntk, resubstitution_params const& ps = {}, resubst { using truthtable_t = kitty::dynamic_truth_table; using truthtable_dc_t = kitty::dynamic_truth_table; - using resub_impl_t = detail::resubstitution_impl, truthtable_dc_t>>>; + using functor_t = mig_enumerative_resub_functor, truthtable_dc_t>; + using resub_impl_t = detail::resubstitution_impl>; resubstitution_stats st; typename resub_impl_t::engine_st_t engine_st; diff --git a/include/mockturtle/algorithms/mig_resyn_engines.hpp b/include/mockturtle/algorithms/mig_resyn_engines.hpp index 5812a4717..0ed643037 100644 --- a/include/mockturtle/algorithms/mig_resyn_engines.hpp +++ b/include/mockturtle/algorithms/mig_resyn_engines.hpp @@ -1,5 +1,5 @@ /* mockturtle: C++ logic network library - * Copyright (C) 2018-2020 EPFL + * Copyright (C) 2018-2021 EPFL * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation diff --git a/include/mockturtle/algorithms/resubstitution.hpp b/include/mockturtle/algorithms/resubstitution.hpp index 08004218a..0b1dc1484 100644 --- a/include/mockturtle/algorithms/resubstitution.hpp +++ b/include/mockturtle/algorithms/resubstitution.hpp @@ -1,5 +1,5 @@ /* mockturtle: C++ logic network library - * Copyright (C) 2018-2020 EPFL + * Copyright (C) 2018-2021 EPFL * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -649,11 +649,6 @@ class resubstitution_impl pbar( i, i, candidates, st.estimated_gain ); - if ( ntk.is_dead( n ) ) - { - return true; /* next */ - } - /* compute cut, collect divisors, compute MFFC */ mffc_result_t potential_gain; const auto collector_success = call_with_stopwatch( st.time_divs, [&]() {