diff --git a/include/mockturtle/algorithms/dont_cares.hpp b/include/mockturtle/algorithms/dont_cares.hpp index 3d2857cac..d20c1c69e 100644 --- a/include/mockturtle/algorithms/dont_cares.hpp +++ b/include/mockturtle/algorithms/dont_cares.hpp @@ -63,10 +63,15 @@ namespace mockturtle * \param max_tfi_inputs Maximum number of inputs in the transitive fanin. */ template -kitty::dynamic_truth_table satisfiability_dont_cares( Ntk const& ntk, std::vector> const& leaves, uint32_t max_tfi_inputs = 16u ) +kitty::dynamic_truth_table satisfiability_dont_cares( Ntk const& ntk, std::vector> const& leaves, uint64_t max_tfi_inputs = 16u ) { - auto extended_leaves = reconv_cut( reconv_cut_params{max_tfi_inputs} )( ntk, leaves ); - + reconvergence_driven_cut_parameters ps; + ps.max_leaves = max_tfi_inputs; + reconvergence_driven_cut_statistics st; + + detail::reconvergence_driven_cut_impl cuts( ntk, ps, st ) ; + auto const extended_leaves = cuts.run( leaves ).first; + fanout_view fanout_ntk{ntk}; fanout_ntk.clear_visited(); diff --git a/include/mockturtle/algorithms/extract_linear.hpp b/include/mockturtle/algorithms/extract_linear.hpp index d4130b99a..c0fc9c1f4 100644 --- a/include/mockturtle/algorithms/extract_linear.hpp +++ b/include/mockturtle/algorithms/extract_linear.hpp @@ -98,6 +98,7 @@ extract_linear_circuit( xag_network const& xag ) } ); for ( auto const& [a, b, _] : and_tuples ) { + (void)_; dest.create_po( a ); dest.create_po( b ); } diff --git a/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp b/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp index e06eb177d..c2390e9bd 100644 --- a/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp +++ b/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp @@ -139,8 +139,9 @@ class xag_minmc_resynthesis for ( auto i = 0u; i < detail::minmc_xags.size(); ++i ) { - for ( auto const& [cls, word, repr, expr] : detail::minmc_xags[i] ) + for ( auto const& [_, word, repr, expr] : detail::minmc_xags[i] ) { + (void)_; db_[i][word] = repr; st_.db_size += sizeof( word ) + sizeof( repr ) + sizeof( uint32_t ) * repr.size(); } diff --git a/include/mockturtle/algorithms/reconv_cut.hpp b/include/mockturtle/algorithms/reconv_cut.hpp index 09bba33ef..27f67851b 100644 --- a/include/mockturtle/algorithms/reconv_cut.hpp +++ b/include/mockturtle/algorithms/reconv_cut.hpp @@ -1,5 +1,5 @@ /* mockturtle: C++ logic network library - * Copyright (C) 2018-2019 EPFL + * Copyright (C) 2018-2020 EPFL * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,193 +25,335 @@ /*! \file reconv_cut.hpp - \brief Reconvergence-driven cut + \brief Implements reconvergence-driven cuts (based on ABC's + implementation in `abcReconv.c` by Alan Mishchenko). \author Heinz Riener */ #pragma once -#include -#include - #include "../traits.hpp" -#include "../utils/node_map.hpp" + +#include +#include +#include namespace mockturtle { -/*! \brief Parameters for reconvergence_driven_cut. +/*! \brief Parameters for reconvergence-driven cut computation + * + * The data structure `reconvergence_driven_cut_parameters` holds configurable parameters + * with default arguments for `reconvergence_driven_cut_impl*`. + */ +struct reconvergence_driven_cut_parameters +{ + /* Maximum number of leaves */ + uint64_t max_leaves{8u}; + + /* Skip nodes with many fanouts */ + uint64_t max_fanouts{100000u}; + + /* Initially reserve memory for a fixed number of nodes */ + uint64_t reserve_memory_for_nodes{300u}; +}; + +/*! \brief Statistics for reconvergence-driven cut computation * - * The data structure `reconv_cut_params` holds configurable parameters - * with default arguments for `reconv_cut`. + * The data structure `reconvergence_driven_cut_statistics` holds data + * collected when running a reconvergence-driven cut computation + * algorithm. */ -struct reconv_cut_params +struct reconvergence_driven_cut_statistics { - /*! \brief Maximum number of leaves for a cut. */ - uint32_t cut_size{10u}; + /* Total number of calls */ + uint64_t num_calls{0}; + + /* Total number of leaves */ + uint64_t num_leaves{0}; + + /* Total number of nodes */ + uint64_t num_nodes{0}; }; /*! \cond PRIVATE */ namespace detail { -template -class compute_fanin_cut +template +class reconvergence_driven_cut_impl { public: - explicit compute_fanin_cut( Ntk const& ntk, std::vector> const& pivots, reconv_cut_params const& ps ) - : _ntk( ntk ), _pivots( pivots ), _ps( ps ), _values( ntk ) - { - assert( _pivots.size() > 0 ); - } + using parameters_type = reconvergence_driven_cut_parameters; + using statistics_type = reconvergence_driven_cut_statistics; + + using node = typename Ntk::node; + using signal = typename Ntk::signal; public: - std::vector> run() + explicit reconvergence_driven_cut_impl( Ntk const& ntk, reconvergence_driven_cut_parameters const& ps, reconvergence_driven_cut_statistics& st ) + : ntk( ntk ) + , ps( ps ) + , st( st ) { - _values.reset(); - std::vector> cut( _pivots ); - for ( const auto& p : _pivots ) + leaves.reserve( ps.max_leaves ); + if constexpr( compute_nodes ) { - _values[p] = 1; + nodes.reserve( ps.reserve_memory_for_nodes ); } - compute_cut_recur( cut ); - return cut; } -protected: - void compute_cut_recur( std::vector>& cut ) + std::pair, std::vector> run( std::vector const& pivots ) { - assert( cut.size() <= _ps.cut_size && "cut-size overflow" ); - std::sort( cut.begin(), cut.end(), [this]( node const& a, node const& b ) { return cost( a ) < cost( b ); } ); + assert( pivots.size() > 0u ); - /* find the first non-pi node to extend the cut (because the vector is sorted, the non-pi is cost-minimal) */ - auto const it = std::find_if( cut.begin(), cut.end(), [&]( auto const& node ) { return !_ntk.is_pi( node ); } ); - if ( cut.end() == it ) + /* prepare for traversal and clean internal state */ + ntk.incr_trav_id(); + nodes.clear(); + leaves.clear(); + + /* collect and mark all pivots */ + for ( const auto& pivot : pivots ) { - /* if all nodes are pis, then the cut cannot be extended */ - return; + if constexpr ( compute_nodes ) + { + nodes.emplace_back( pivot ); + } + ntk.set_visited( pivot, ntk.trav_id() ); } - /* the cost is identical to the number of nodes added to the cut if *it is used to expand the cut */ - auto const c = cost( *it ); - if ( cut.size() + c > _ps.cut_size ) + leaves = pivots; + + if ( leaves.size() > ps.max_leaves ) { - /* if the expansion exceeds the cut_size, then the cut cannot be extended */ - return; + /* special case: cut already overflows at the current node because the cut size limit is very low */ + leaves.clear(); + nodes.clear(); + return { leaves, nodes }; } - /* otherwise expand the cut with the children of *it and mark *it visited (by setting a value) */ - const auto n = *it; - cut.erase( it ); - _ntk.foreach_fanin( n, [&]( signal const& s ) { - auto const& child = _ntk.get_node( s ); - if ( !_ntk.is_constant( child ) && std::find( cut.begin(), cut.end(), child ) == cut.end() && !_values[child] ) - { - cut.push_back( child ); - _values[child] = 1; - } - } ); + /* compute the cut */ + while ( construct_cut() ); + assert( leaves.size() <= ps.max_leaves ); + + /* update statistics */ + ++st.num_calls; + st.num_leaves += leaves.size(); + st.num_nodes += nodes.size(); - assert( cut.size() <= _ps.cut_size ); - compute_cut_recur( cut ); + return { leaves, nodes }; } - inline int32_t cost( node const& n ) const +private: + bool construct_cut() { - int32_t current_cost = -1; - _ntk.foreach_fanin( n, [&]( signal const& s ) { - auto const& child = _ntk.get_node( s ); - if ( !_ntk.is_constant( child ) && !_values[child] ) + uint64_t best_cost{std::numeric_limits::max()}; + std::optional best_fanin; + uint64_t best_position; + + /* evaluate fanins of the cut */ + uint64_t position{0}; + for ( const auto& l : leaves ) + { + uint64_t const current_cost{cost( l )}; + if constexpr ( sort_equal_cost_by_level ) { - ++current_cost; + if ( best_cost > current_cost || + ( best_cost == current_cost && best_fanin && ntk.level( l ) > ntk.level( *best_fanin ) ) ) + { + best_cost = current_cost; + best_fanin = std::make_optional( l ); + best_position = position; + } } - } ); - return current_cost; + else + { + if ( best_cost > current_cost ) + { + best_cost = current_cost; + best_fanin = std::make_optional( l ); + best_position = position; + } + } + + if ( best_cost == 0u ) + { + break; + } + + ++position; + } + + if ( !best_fanin ) + { + return false; + } + + if ( leaves.size() - 1 + best_cost > ps.max_leaves ) + { + return false; + } + + /* remove the best node from the array */ + leaves.erase( std::begin( leaves ) + best_position ); + + /* add the fanins of best to leaves and nodes */ + ntk.foreach_fanin( *best_fanin, [&]( signal const& fi ){ + node const& n = ntk.get_node( fi ); + if ( n != 0 && ( ntk.visited( n ) != ntk.trav_id() ) ) + { + ntk.set_visited( n, ntk.trav_id() ); + if constexpr ( compute_nodes ) + { + nodes.emplace_back( n ); + } + leaves.emplace_back( n ); + } + }); + + assert( leaves.size() <= ps.max_leaves ); + return true; } -protected: - Ntk const& _ntk; - std::vector> _pivots; - reconv_cut_params const& _ps; - node_map _values; -}; + uint64_t cost( node const& n ) const + { + /* make sure the node is in the construction zone */ + assert( ntk.visited( n ) == ntk.trav_id() ); + + /* cannot expand over a constant or CI node */ + if ( ntk.is_constant( n ) || ntk.is_ci( n ) ) + { + return std::numeric_limits::max(); + } + + /* count the number of leaves that we haven't visited */ + uint64_t cost{0}; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + cost += ntk.visited( ntk.get_node( fi ) ) != ntk.trav_id(); + }); + + /* always accept if the number of leaves does not increase */ + if ( cost < ntk.fanin_size( n ) ) + { + return cost; + } + + /* skip nodes with many fanouts */ + if ( ntk.fanout_size( n ) > ps.max_fanouts ) + { + return std::numeric_limits::max(); + } + + /* return the number of nodes that will be on the leaves if this node is removed */ + return cost; + } + +private: + Ntk const& ntk; + reconvergence_driven_cut_parameters ps; + reconvergence_driven_cut_statistics& st; + + std::vector leaves; + std::vector nodes; +}; /* reconvergence_drive_cut_impl */ -template -class compute_fanout_cut +template +class reconvergence_driven_cut_impl2 { public: - explicit compute_fanout_cut( Ntk const& ntk, std::vector> const& pivots, reconv_cut_params const& ps ) - : _ntk( ntk ), _pivots( pivots ), _ps( ps ), _values( ntk ) + using parameters_type = reconvergence_driven_cut_parameters; + using statistics_type = reconvergence_driven_cut_statistics; + + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +public: + explicit reconvergence_driven_cut_impl2( Ntk const& ntk, reconvergence_driven_cut_parameters const& ps, reconvergence_driven_cut_statistics& st ) + : ntk( ntk ) + , ps( ps ) + , st( st ) { - assert( _pivots.size() > 0 ); } -public: - std::vector> run() + std::pair, std::vector> run( std::vector const& pivots ) { - _values.reset(); - std::vector> cut( _pivots ); - for ( const auto& p : _pivots ) + assert( pivots.size() > 0u ); + + /* prepare for traversal and clean internal state */ + ntk.incr_trav_id(); + nodes.clear(); + leaves.clear(); + assert( nodes.empty() ); + + for ( const auto& pivot : pivots ) { - _values[p] = 1; + ntk.set_visited( pivot, ntk.trav_id() ); } - compute_cut_recur( cut ); - return cut; - } -protected: - bool has_internal_fanout( node const& n ) - { - bool has = false; - _ntk.foreach_fanout( n, [&]( const auto& ) { - has = true; - return false; - } ); - return has; + while ( construct_cut() ); + assert( leaves.size() <= ps.max_leaves ); + + /* update statistics */ + ++st.num_calls; + st.num_leaves += leaves.size(); + st.num_nodes += nodes.size(); + + return { leaves, nodes }; } - void compute_cut_recur( std::vector>& cut ) + bool construct_cut() { - assert( cut.size() <= _ps.cut_size && "cut-size overflow" ); - std::sort( cut.begin(), cut.end(), [this]( node const& a, node const& b ) { return cost( a ) < cost( b ); } ); - - /* find the first non-po node to extend the cut (because the vector is sorted, the non-po is cost-minimal) */ - auto const it = std::find_if( cut.begin(), cut.end(), [&]( auto const& node ) { return has_internal_fanout( node ); } ); - if ( cut.end() == it ) + assert( leaves.size() <= ps.max_leaves && "cut-size overflow" ); + std::sort( std::begin( leaves ), std::end( leaves ), + [this]( node const& a, node const& b ) + { + return cost( a ) < cost( b ); + } ); + + /* find the first non-pi node to extend the cut (because the vector is sorted, this non-pi is cost-minimal) */ + auto const it = std::find_if( std::begin( leaves ), std::end( leaves ), + [&]( node const& n ) + { + return !ntk.is_ci( n ); + } ); + if ( std::end( leaves ) == it ) { - /* if all nodes are pos, then the cut cannot be extended */ - return; + /* if all nodes are pis, then the cut cannot be extended */ + return false; } - /* the cost is identical to the number of nodes added to the cut if *it is used to expand the cut */ - auto const c = cost( *it ); - if ( cut.size() + c > _ps.cut_size ) + /* the cost is identical to the number of nodes added to `leaves` if *it is used to expand leaves */ + int64_t const c = cost( *it ); + if ( leaves.size() + c > ps.max_leaves ) { /* if the expansion exceeds the cut_size, then the cut cannot be extended */ - return; + return false; } - /* otherwise expand the cut with the parents of *it and mark *it visited (by setting a value) */ - const auto n = *it; - cut.erase( it ); - _ntk.foreach_fanout( n, [&]( node const& parent ) { - if ( std::find( cut.begin(), cut.end(), parent ) == cut.end() && !_values[parent] ) - { - cut.push_back( parent ); - _values[parent] = 1; - } - } ); - - assert( cut.size() <= _ps.cut_size ); - compute_cut_recur( cut ); + /* otherwise expand the cut with the children of *it and mark *it visited */ + node const n = *it; + leaves.erase( it ); + ntk.foreach_fanin( n, [&]( signal const& fi ){ + node const& child = ntk.get_node( fi ); + if ( !ntk.is_constant( child ) && std::find( std::begin( leaves ), std::end( leaves ), child ) == std::end( leaves ) && ntk.visited( child ) != ntk.trav_id() ) + { + leaves.emplace_back( child ); + ntk.set_visited( child, ntk.trav_id() ); + } + }); + + assert( leaves.size() <= ps.max_leaves ); + return true; } - inline int32_t cost( node const& n ) const + /* counts the number of non-constant leaves */ + int64_t cost( node const &n ) const { int32_t current_cost = -1; - _ntk.foreach_fanout( n, [&]( node const& parent ) { - if ( !_values[parent] ) + ntk.foreach_fanin( n, [&]( signal const& s ) { + auto const& child = ntk.get_node( s ); + if ( !ntk.is_constant( child ) ) { ++current_cost; } @@ -219,122 +361,105 @@ class compute_fanout_cut return current_cost; } -protected: - Ntk const& _ntk; - std::vector> _pivots; - reconv_cut_params const& _ps; - node_map _values; -}; +private: + Ntk const& ntk; + reconvergence_driven_cut_parameters ps; + reconvergence_driven_cut_statistics& st; -} /* namespace detail */ + std::vector leaves; + std::vector nodes; +}; /* reconvergence_drive_cut_impl2 */ + +template +std::pair>, std::vector>> reconvergence_driven_cut( Ntk const& ntk, std::vector> const& pivots, reconvergence_driven_cut_parameters const& ps, reconvergence_driven_cut_statistics& st ) +{ + return Impl( ntk, ps, st ).run( pivots ); +} + +} /* detail */ /*! \endcond */ -/*! \brief Reconvergence-driven cuts towards inputs. +/*! \brief Reconvergence-driven cut towards inputs. * * This class implements a generation algorithm for * reconvergence-driven cuts. The cut grows towards the primary - * inputs starting from a pivot node. + * inputs starting from a set of pivot nodes. * * **Required network functions:** * - `is_constant` * - `is_pi` * - `get_node` + * - `visited` + * - `has_visited` * - `foreach_fanin` * */ -struct reconv_cut +template +std::pair>, std::vector>> reconvergence_driven_cut( Ntk const& ntk, std::vector> const& pivots, reconvergence_driven_cut_parameters const& ps = {}, reconvergence_driven_cut_statistics *pst = nullptr ) { -public: - explicit reconv_cut( reconv_cut_params const& ps = {} ) - : _ps( ps ) + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); + static_assert( has_is_ci_v, "Ntk does not implement the is_ci method" ); + static_assert( has_get_node_v, "Ntk does not implement the get_node method" ); + static_assert( has_visited_v, "Ntk does not implement the has_visited method" ); + static_assert( has_set_visited_v, "Ntk does not implement the set_visited method" ); + static_assert( has_foreach_fanin_v, "Ntk does not implement the foreach_fanin method" ); + if constexpr ( sort_equal_cost_by_level ) { + static_assert( has_level_v, "Ntk does not implement the level method" ); } - template - std::vector> operator()( Ntk const& ntk, node const& pivot ) - { - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); - static_assert( has_is_pi_v, "Ntk does not implement the is_pi method" ); - static_assert( has_get_node_v, "Ntk does not implement the is_pi method" ); - static_assert( has_foreach_fanin_v, "Ntk does not implement the is_pi method" ); - - detail::compute_fanin_cut cut_generator( ntk, {pivot}, _ps ); - - return cut_generator.run(); - } + using Impl = detail::reconvergence_driven_cut_impl; - template - std::vector> operator()( Ntk const& ntk, std::vector> const& pivots ) + reconvergence_driven_cut_statistics st; + auto const result = detail::reconvergence_driven_cut( ntk, pivots, ps, st ); + if ( pst ) { - assert( pivots.size() > 0u && "pivots must not be empty" ); - - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); - static_assert( has_is_pi_v, "Ntk does not implement the is_pi method" ); - static_assert( has_get_node_v, "Ntk does not implement the is_pi method" ); - static_assert( has_foreach_fanin_v, "Ntk does not implement the is_pi method" ); - - detail::compute_fanin_cut cut_generator( ntk, pivots, _ps ); - - return cut_generator.run(); + *pst = st; } + return result; +} -private: - reconv_cut_params _ps; -}; - -/*! \brief Reconvergence-driven cuts towards outputs. +/*! \brief Reconvergence-driven cut towards inputs. * * This class implements a generation algorithm for * reconvergence-driven cuts. The cut grows towards the primary - * outputs starting from a pivot node. + * inputs starting from a single pivot node. * * **Required network functions:** * - `is_constant` * - `is_pi` * - `get_node` - * - `foreach_fanout` + * - `visited` + * - `has_visited` + * - `foreach_fanin` * */ -struct reconv_fanout_cut +template +std::pair>, std::vector>> reconvergence_driven_cut( Ntk const& ntk, node const& pivot, reconvergence_driven_cut_parameters const& ps = {}, reconvergence_driven_cut_statistics *pst = nullptr ) { -public: - explicit reconv_fanout_cut( reconv_cut_params const& ps = {} ) - : _ps( ps ) - { - } - - template - std::vector> operator()( Ntk const& ntk, node const& pivot ) - { - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); - static_assert( has_is_pi_v, "Ntk does not implement the is_pi method" ); - static_assert( has_get_node_v, "Ntk does not implement the is_pi method" ); - static_assert( has_foreach_fanout_v, "Ntk does not implement the foreach_fanout method" ); - - detail::compute_fanout_cut cut_generator( ntk, {pivot}, _ps ); - return cut_generator.run(); - } - - template - std::vector> operator()( Ntk const& ntk, std::vector> const& pivots ) - { - assert( pivots.size() > 0u && "pivots must not be empty" ); - - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); - static_assert( has_is_pi_v, "Ntk does not implement the is_pi method" ); - static_assert( has_get_node_v, "Ntk does not implement the is_pi method" ); - static_assert( has_foreach_fanout_v, "Ntk does not implement the foreach_fanout method" ); + return reconvergence_driven_cut( ntk, std::vector>{ pivot }, ps, pst ); +} - detail::compute_fanout_cut cut_generator( ntk, pivots, _ps ); - return cut_generator.run(); - } - -private: - reconv_cut_params _ps; -}; +/*! \brief Reconvergence-driven cut towards inputs. + * + * This class implements a generation algorithm for + * reconvergence-driven cuts. The cut grows towards the primary + * inputs starting from a single pivot signal. + * + * **Required network functions:** + * - `is_constant` + * - `is_pi` + * - `get_node` + * - `visited` + * - `has_visited` + * - `foreach_fanin` + * + */ +template +std::pair>, std::vector>> reconvergence_driven_cut( Ntk const& ntk, signal const& pivot, reconvergence_driven_cut_parameters const& ps = {}, reconvergence_driven_cut_statistics *pst = nullptr ) +{ + return reconvergence_driven_cut( ntk, std::vector>{ ntk.get_node( pivot ) }, ps, pst ); +} -} /* namespace mockturtle */ +} /* mockturtle */ diff --git a/include/mockturtle/algorithms/reconv_cut2.hpp b/include/mockturtle/algorithms/reconv_cut2.hpp deleted file mode 100644 index 444577fd8..000000000 --- a/include/mockturtle/algorithms/reconv_cut2.hpp +++ /dev/null @@ -1,210 +0,0 @@ -/* mockturtle: C++ logic network library - * Copyright (C) 2018-2019 EPFL - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/*! - \file reconv_cut.hpp - \brief Reconvergence-driven cut - - Based on `abcReconv.c` - - \author Heinz Riener -*/ - -#pragma once - -#include "../traits.hpp" - -#include -#include - -namespace mockturtle -{ - -template -struct cut_manager -{ - explicit cut_manager( int node_size_max, int node_fan_stop = 100000 ) - : node_size_max( node_size_max ) - , node_fan_stop( node_fan_stop ) - { - } - - /* \brief limit on the size of the supernode */ - int node_size_max; - - /* \brief limit on the size of the supernode */ - int node_fan_stop; - - /* \brief fanins of the collapsed node (the cut) */ - std::vector> node_leaves; - - /* \brief visited nodes */ - std::vector> visited; -}; - -namespace detail -{ - -template -int node_get_leaf_cost_one( Ntk const& ntk, typename Ntk::node const &node, int fanin_limit ) -{ - /* make sure the node is in the construction zone */ - assert( ntk.visited( node ) == ntk.trav_id() ); - - /* cannot expand over the PI node */ - if ( ntk.is_constant( node ) || ntk.is_pi( node ) ) - return 999; - - /* get the cost of the cone */ - uint32_t cost = 0; - ntk.foreach_fanin( node, [&]( const auto& f ){ - cost += ( ntk.visited( ntk.get_node( f ) ) == ntk.trav_id() ) ? 0 : 1; - } ); - - /* always accept if the number of leaves does not increase */ - if ( cost < ntk.fanin_size( node ) ) - return cost; - - /* skip nodes with many fanouts */ - if ( int( ntk.fanout_size( node ) ) > fanin_limit ) - return 999; - - /* return the number of nodes that will be on the leaves if this node is removed */ - return cost; -} - -template -bool node_build_cut_level_one_int( Ntk const& ntk, std::vector& visited, std::vector& leaves, uint64_t size_limit, int fanin_limit ) -{ - uint32_t best_cost = 100; - - std::optional best_fanin; - int best_pos; - - /* evaluate fanins of the cut */ - auto pos = 0; - for ( const auto& l : leaves ) - { - uint32_t const cost_curr = node_get_leaf_cost_one( ntk, l, fanin_limit ); - if ( best_cost > cost_curr || - ( best_cost == cost_curr && best_fanin && ntk.level( l ) > ntk.level( *best_fanin ) ) ) - { - best_cost = cost_curr; - best_fanin = std::make_optional( l ); - best_pos = pos; - } - - if ( best_cost == 0 ) - break; - - ++pos; - } - - if ( !best_fanin ) - return false; - - // assert( best_cost < max_fanin_of_graph_structure ); - if ( leaves.size() - 1 + best_cost > size_limit ) - return false; - - /* remove the best node from the array */ - leaves.erase( leaves.begin() + best_pos ); - - /* add the fanins of best to leaves and visited */ - ntk.foreach_fanin( *best_fanin, [&]( const auto& f ){ - auto const& n = ntk.get_node( f ); - if ( n != 0 && ( ntk.visited( n ) != ntk.trav_id() ) ) - { - ntk.set_visited( n, ntk.trav_id() ); - visited.push_back( n ); - leaves.push_back( n ); - } - }); - - assert( leaves.size() <= size_limit ); - - return true; -} - -template -std::vector node_find_cut( cut_manager& mgr, Ntk const& ntk, typename Ntk::node const& root ) -{ - ntk.incr_trav_id(); - - /* start the visited nodes and mark them */ - mgr.visited.clear(); - mgr.visited.push_back( root ); - ntk.set_visited( root, 1 ); - ntk.foreach_fanin( root, [&]( const auto& f ){ - auto const& n = ntk.get_node( f ); - if ( n == 0 ) return true; - mgr.visited.push_back( n ); - ntk.set_visited( n, ntk.trav_id() ); - return true; - } ); - - /* start the cut */ - mgr.node_leaves.clear(); - ntk.foreach_fanin( root, [&]( const auto& f ){ - auto const& n = ntk.get_node( f ); - if ( n == 0 ) return true; - mgr.node_leaves.push_back( n ); - return true; - } ); - - if ( mgr.node_leaves.size() > uint32_t( mgr.node_size_max ) ) - { - /* special case: cut already overflows at the current node - bc. the cut size limit is very low */ - mgr.node_leaves.clear(); - return {}; - } - - /* compute the cut */ - while ( node_build_cut_level_one_int( ntk, mgr.visited, mgr.node_leaves, mgr.node_size_max, mgr.node_fan_stop ) ); - assert( int( mgr.node_leaves.size() ) <= mgr.node_size_max ); - - return mgr.node_leaves; -} - -} /* namespace detail */ - -template -std::vector> reconv_driven_cut( cut_manager& mgr, Ntk const& ntk, node const& pivot ) -{ - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); - static_assert( has_is_pi_v, "Ntk does not implement the is_pi method" ); - static_assert( has_get_node_v, "Ntk does not implement the is_pi method" ); - static_assert( has_visited_v, "Ntk does not implement the has_visited method" ); - static_assert( has_set_visited_v, "Ntk does not implement the set_visited method" ); - static_assert( has_foreach_fanin_v, "Ntk does not implement the foreach_fanin method" ); - static_assert( has_foreach_fanout_v, "Ntk does not implement the foreach_fanout method" ); - static_assert( has_level_v, "Ntk does not implement the level method" ); - - return detail::node_find_cut( mgr, ntk, pivot ); -} - -} /* namespace mockturtle */ diff --git a/include/mockturtle/algorithms/resubstitution.hpp b/include/mockturtle/algorithms/resubstitution.hpp index a168d567a..d8fac0e64 100644 --- a/include/mockturtle/algorithms/resubstitution.hpp +++ b/include/mockturtle/algorithms/resubstitution.hpp @@ -34,16 +34,17 @@ #pragma once -#include - #include "../traits.hpp" #include "../utils/progress_bar.hpp" #include "../utils/stopwatch.hpp" #include "../views/depth_view.hpp" #include "../views/fanout_view.hpp" + #include "detail/resub_utils.hpp" #include "dont_cares.hpp" -#include "reconv_cut2.hpp" +#include "reconv_cut.hpp" + +#include namespace mockturtle { @@ -152,7 +153,7 @@ struct resubstitution_stats std::cout << fmt::format( "[i] ResubEngine : {:>5.2f} secs\n", to_seconds( time_resub ) ); std::cout << fmt::format( "[i] callback : {:>5.2f} secs\n", to_seconds( time_callback ) ); std::cout << "[i] =========================\n\n"; - // clang-format on + // clang-format on } }; @@ -176,7 +177,7 @@ bool report_fn( Ntk& ntk, typename Ntk::node const& n, typename Ntk::signal cons struct default_collector_stats { - /*! \brief Total number of leaves */ + /*! \brief Total number of leaves. */ uint64_t num_total_leaves{0}; /*! \brief Accumulated runtime for cut computation. */ @@ -198,28 +199,28 @@ struct default_collector_stats std::cout << fmt::format( "[i] MFFC : {:>5.2f} secs\n", to_seconds( time_mffc ) ); std::cout << fmt::format( "[i] divs collect: {:>5.2f} secs\n", to_seconds( time_divs ) ); std::cout << "[i] =========================\n\n"; - // clang-format on + // clang-format on } }; -/*! \brief Prepare the three public data members `leaves`, `divs` and `MFFC` +/*! \brief Prepare the three public data members `leaves`, `divs` and `mffc` * to be ready for usage. * * `leaves`: sufficient support for all divisors * `divs`: divisor nodes that can be used for resubstitution - * `MFFC`: MFFC nodes which are needed to do simulation from - * `leaves`, through `divs` and `MFFC` until the root node, + * `mffc`: MFFC nodes which are needed to do simulation from + * `leaves`, through `divs` and `mffc` until the root node, * but should be excluded from resubstitution. - * The last element of `MFFC` is always the root node. + * The last element of `mffc` is always the root node. * - * `divs` and `MFFC` are in topological order. + * `divs` and `mffc` are in topological order. * - * \param MffcMgr Manager class to compute the potential gain if a + * \param MffcMgr Manager class to compute the potential gain if a * resubstitution exists (number of MFFC nodes when the cost function is circuit size). * \param MffcRes Typename of the return value of `MffcMgr`. - * \param CutMgr Manager class to compute the cut to construct the window. + * \param cut_comp Manager class to compute reconvergence-driven cuts. */ -template, typename MffcRes = uint32_t, class CutMgr = cut_manager> +template, typename MffcRes = uint32_t, typename cut_comp = detail::reconvergence_driven_cut_impl> class default_divisor_collector { public: @@ -227,9 +228,12 @@ class default_divisor_collector using mffc_result_t = MffcRes; using node = typename Ntk::node; + using cut_comp_parameters_type = typename cut_comp::parameters_type; + using cut_comp_statistics_type = typename cut_comp::statistics_type; + public: explicit default_divisor_collector( Ntk const& ntk, resubstitution_params const& ps, stats& st ) - : ntk( ntk ), ps( ps ), st( st ), cut_mgr( ps.max_pis ) + : ntk( ntk ), ps( ps ), st( st ), cuts( ntk, cut_comp_parameters_type{ps.max_pis}, cuts_st ) { } @@ -243,14 +247,14 @@ class default_divisor_collector /* compute a reconvergence-driven cut */ leaves = call_with_stopwatch( st.time_cuts, [&]() { - return reconv_driven_cut( cut_mgr, ntk, n ); + return cuts.run( { n } ).first; }); st.num_total_leaves += leaves.size(); /* collect the MFFC */ MffcMgr mffc_mgr( ntk ); potential_gain = call_with_stopwatch( st.time_mffc, [&]() { - return mffc_mgr.run( n, leaves, MFFC ); + return mffc_mgr.run( n, leaves, mffc ); }); /* collect the divisor nodes in the cut */ @@ -300,7 +304,7 @@ class default_divisor_collector } /* mark nodes in the MFFC */ - for ( const auto& t : MFFC ) + for ( const auto& t : mffc ) { ntk.set_value( t, 1 ); } @@ -309,25 +313,25 @@ class default_divisor_collector collect_divisors_rec( root ); /* unmark the current MFFC */ - for ( const auto& t : MFFC ) + for ( const auto& t : mffc ) { ntk.set_value( t, 0 ); } /* check if the number of divisors is not exceeded */ - if ( divs.size() - leaves.size() + MFFC.size() >= ps.max_divisors - ps.max_pis ) + if ( divs.size() - leaves.size() + mffc.size() >= ps.max_divisors - ps.max_pis ) { return false; } /* get the number of divisors to collect */ - int32_t limit = ps.max_divisors - ps.max_pis - ( uint32_t( divs.size() ) + 1 - uint32_t( leaves.size() ) + uint32_t( MFFC.size() ) ); + int32_t limit = ps.max_divisors - ps.max_pis - ( uint32_t( divs.size() ) + 1 - uint32_t( leaves.size() ) + uint32_t( mffc.size() ) ); /* explore the fanouts, which are not in the MFFC */ int32_t counter = 0; bool quit = false; - /* NOTE: this is tricky and cannot be converted to a range-based loop */ + /* note: this is tricky and cannot be converted to a range-based loop */ auto size = divs.size(); for ( auto i = 0u; i < size; ++i ) { @@ -393,24 +397,25 @@ class default_divisor_collector } } - /* Note: different from the previous version, now we do not add MFFC nodes into divs */ - assert( root == MFFC.at( MFFC.size() - 1u ) ); - assert( divs.size() + MFFC.size() - leaves.size() <= ps.max_divisors - ps.max_pis ); + /* note: different from the previous version, now we do not add MFFC nodes into divs */ + assert( root == mffc.at( mffc.size() - 1u ) ); + assert( divs.size() + mffc.size() - leaves.size() <= ps.max_divisors - ps.max_pis ); return true; } private: Ntk const& ntk; - resubstitution_params const& ps; + resubstitution_params ps; stats& st; - CutMgr cut_mgr; + cut_comp cuts; + cut_comp_statistics_type cuts_st; public: std::vector leaves; std::vector divs; - std::vector MFFC; + std::vector mffc; }; template @@ -442,16 +447,16 @@ struct window_resub_stats std::cout << "[i] ======== Details ========\n"; functor_st.report(); std::cout << "[i] =========================\n\n"; - // clang-format on + // clang-format on } }; /*! \brief Window-based resubstitution engine. - * + * * This engine computes the complete truth tables of nodes within a window * with the leaves as inputs. It does not verify the resubstitution candidates * given by the resubstitution functor. This engine requires the divisor - * collector to prepare three data members: `leaves`, `divs` and `MFFC`. + * collector to prepare three data members: `leaves`, `divs` and `mffc`. * * Required interfaces of the resubstitution functor: * - Constructor: `resub_fn( Ntk const& ntk, Simulator const& sim,` @@ -476,7 +481,7 @@ template; using mffc_result_t = MffcRes; @@ -488,11 +493,11 @@ class window_based_resub_engine { } - std::optional run( node const& n, std::vector const& leaves, std::vector const& divs, std::vector const& MFFC, mffc_result_t potential_gain, uint32_t& last_gain ) + std::optional run( node const& n, std::vector const& leaves, std::vector const& divs, std::vector const& mffc, mffc_result_t potential_gain, uint32_t& last_gain ) { /* simulate the collected divisors */ call_with_stopwatch( st.time_sim, [&]() { - simulate( leaves, divs, MFFC ); + simulate( leaves, divs, mffc ); }); auto care = kitty::create( static_cast( leaves.size() ) ); @@ -519,12 +524,12 @@ class window_based_resub_engine } private: - void simulate( std::vector const& leaves, std::vector const& divs, std::vector const& MFFC ) + void simulate( std::vector const& leaves, std::vector const& divs, std::vector const& mffc ) { sim.resize(); - for ( auto i = 0u; i < divs.size() + MFFC.size(); ++i ) + for ( auto i = 0u; i < divs.size() + mffc.size(); ++i ) { - const auto d = i < divs.size() ? divs.at( i ) : MFFC.at( i - divs.size() ); + const auto d = i < divs.size() ? divs.at( i ) : mffc.at( i - divs.size() ); /* skip constant 0 */ if ( d == 0 ) @@ -550,7 +555,7 @@ class window_based_resub_engine /* normalize truth tables */ sim.normalize( divs ); - sim.normalize( MFFC ); + sim.normalize( mffc ); } private: @@ -573,7 +578,7 @@ class window_based_resub_engine * Currently only `default_divisor_collector` is implemented, but * a frontier-based approach may be integrated in the future. * When using `window_based_resub_engine`, the `DivCollector` should prepare - * three public data members: `leaves`, `divs`, and `MFFC` (see documentation + * three public data members: `leaves`, `divs`, and `mffc` (see documentation * of `default_divisor_collector` for details). When using `simulation_based_resub_engine`, * only `divs` is needed. */ @@ -666,9 +671,9 @@ class resubstitution_impl /* try to find a resubstitution with the divisors */ auto g = call_with_stopwatch( st.time_resub, [&]() { - if constexpr ( ResubEngine::require_leaves_and_MFFC ) /* window-based */ + if constexpr ( ResubEngine::require_leaves_and_mffc ) /* window-based */ { - return resub_engine.run( n, collector.leaves, collector.divs, collector.MFFC, potential_gain, last_gain ); + return resub_engine.run( n, collector.leaves, collector.divs, collector.mffc, potential_gain, last_gain ); } else /* simulation-based */ { diff --git a/include/mockturtle/algorithms/sim_resub.hpp b/include/mockturtle/algorithms/sim_resub.hpp index 082413544..40ce5625b 100644 --- a/include/mockturtle/algorithms/sim_resub.hpp +++ b/include/mockturtle/algorithms/sim_resub.hpp @@ -772,7 +772,7 @@ template; using mffc_result_t = MffcRes; @@ -1017,4 +1017,4 @@ void sim_resubstitution( Ntk& ntk, resubstitution_params const& ps = {}, resubst } } -} /* namespace mockturtle */ \ No newline at end of file +} /* namespace mockturtle */ diff --git a/include/mockturtle/generators/self_dualize.hpp b/include/mockturtle/generators/self_dualize.hpp index 8c8124b42..d76e9a0b2 100644 --- a/include/mockturtle/generators/self_dualize.hpp +++ b/include/mockturtle/generators/self_dualize.hpp @@ -70,12 +70,13 @@ aig_network self_dualize_aig( aig_network const& src_aig ) node_to_signal_two[n] = !pi; }); - reconv_cut_params ps; - ps.cut_size = 99999999u; - src_aig.foreach_po( [&]( const auto& f ){ - reconv_cut cutgen( ps ); + reconvergence_driven_cut_parameters ps; + ps.max_leaves = 99999999u; + reconvergence_driven_cut_statistics st; + detail::reconvergence_driven_cut_impl cut_generator( src_aig, ps, st ); - auto leaves = cutgen( src_aig, src_aig.get_node( f ) ); + src_aig.foreach_po( [&]( const auto& f ){ + auto leaves = cut_generator.run( { src_aig.get_node( f ) } ).first; std::sort( std::begin( leaves ), std::end( leaves ) ); /* check if all leaves are pis */ diff --git a/include/mockturtle/mockturtle.hpp b/include/mockturtle/mockturtle.hpp index f8372165b..62197e014 100644 --- a/include/mockturtle/mockturtle.hpp +++ b/include/mockturtle/mockturtle.hpp @@ -65,7 +65,7 @@ #include "mockturtle/algorithms/cnf.hpp" #include "mockturtle/algorithms/miter.hpp" #include "mockturtle/algorithms/collapse_mapped.hpp" -#include "mockturtle/algorithms/reconv_cut2.hpp" +#include "mockturtle/algorithms/reconv_cut.hpp" #include "mockturtle/algorithms/refactoring.hpp" #include "mockturtle/algorithms/node_resynthesis/exact.hpp" #include "mockturtle/algorithms/node_resynthesis/shannon.hpp" @@ -89,7 +89,6 @@ #include "mockturtle/algorithms/node_resynthesis.hpp" #include "mockturtle/algorithms/linear_resynthesis.hpp" #include "mockturtle/algorithms/mig_resub.hpp" -#include "mockturtle/algorithms/reconv_cut.hpp" #include "mockturtle/algorithms/resubstitution.hpp" #include "mockturtle/algorithms/aig_resub.hpp" #include "mockturtle/algorithms/circuit_validator.hpp" diff --git a/include/mockturtle/views/cnf_view.hpp b/include/mockturtle/views/cnf_view.hpp index eb1654f33..973396fa5 100644 --- a/include/mockturtle/views/cnf_view.hpp +++ b/include/mockturtle/views/cnf_view.hpp @@ -548,6 +548,7 @@ class cnf_view : public detail::cnf_view_impl } else { + (void)add_var; const auto v = solver_.add_variable(); assert( v == var( n ) ); (void)v; diff --git a/test/algorithms/extract_linear.cpp b/test/algorithms/extract_linear.cpp index 706700f9a..a039047cd 100644 --- a/test/algorithms/extract_linear.cpp +++ b/test/algorithms/extract_linear.cpp @@ -23,8 +23,8 @@ TEST_CASE( "Extract linear part from MAJ XAG", "[extract_linear]" ) CHECK( 1u == xag.num_pos() ); CHECK( 4u == xag.num_gates() ); - const auto [linxag, signals] = extract_linear_circuit( xag ); - + const auto [linxag, _] = extract_linear_circuit( xag ); + (void)_; CHECK( 4u == linxag.num_pis() ); CHECK( 3u == linxag.num_pos() ); CHECK( 3u == linxag.num_gates() ); diff --git a/test/algorithms/reconv_cut.cpp b/test/algorithms/reconv_cut.cpp index 3278df98b..e5680b574 100644 --- a/test/algorithms/reconv_cut.cpp +++ b/test/algorithms/reconv_cut.cpp @@ -1,15 +1,13 @@ #include -#include -#include - #include #include #include +#include using namespace mockturtle; -TEST_CASE( "generate fanin-cuts for an AIG", "[cut_generation]" ) +TEST_CASE( "generate fanin-cuts for an AIG using function API", "[reconv_cut]" ) { aig_network aig; const auto a = aig.create_pi(); @@ -20,20 +18,26 @@ TEST_CASE( "generate fanin-cuts for an AIG", "[cut_generation]" ) const auto f4 = aig.create_nand( f2, f3 ); aig.create_po( f4 ); + /* some ordered container */ using set_t = std::set>; - /* helper functions for generating leaves */ - auto leaves = [&]( const auto& p, unsigned size = 10u ){ - const auto leaves = reconv_cut( reconv_cut_params{ size } )( aig, aig.get_node( p ) ); - return set_t( leaves.begin(), leaves.end() ); + /* helper functions for extracting leave sets */ + auto leaves = [&]( auto const& p, uint64_t size = 10u ){ + const auto leaves = reconvergence_driven_cut( aig, p, reconvergence_driven_cut_parameters{ size } ).first; + return set_t( std::begin( leaves ), std::end( leaves ) ); }; - CHECK( leaves( a ) == set_t{ aig.get_node( a ) } ); - CHECK( leaves( b ) == set_t{ aig.get_node( b ) } ); + /* for all CIs i : rrcut( i ) == { i } */ + CHECK( leaves( a ) == set_t{ aig.get_node( a ) } ); + CHECK( leaves( b ) == set_t{ aig.get_node( b ) } ); + + /* for all internal nodes n : rrcut( n ) == { p | p is CI and p \in TFI( n ) } and cut-size large enough */ CHECK( leaves( f1 ) == set_t{ aig.get_node( a ), aig.get_node( b ) } ); CHECK( leaves( f2 ) == set_t{ aig.get_node( a ), aig.get_node( b ) } ); CHECK( leaves( f3 ) == set_t{ aig.get_node( a ), aig.get_node( b ) } ); CHECK( leaves( f4 ) == set_t{ aig.get_node( a ), aig.get_node( b ) } ); + + /* some special cases if cut-size is restricted */ CHECK( leaves( f4, 1u ) == set_t{ aig.get_node( f4 ) } ); CHECK( leaves( f4, 2u ) == set_t{ aig.get_node( f2 ), aig.get_node( f3 ) } ); CHECK( leaves( f4, 3u ) == set_t{ aig.get_node( a ), aig.get_node( b ) } ); @@ -41,8 +45,11 @@ TEST_CASE( "generate fanin-cuts for an AIG", "[cut_generation]" ) CHECK( leaves( f4, 3u ) == set_t{ aig.get_node( a ), aig.get_node( b ) } ); } -TEST_CASE( "generate fanout-cuts for an AIG", "[cut_generation]" ) +TEST_CASE( "generate fanin-cuts for an AIG using manager class API", "[reconv_cut]" ) { + using cuts_impl = detail::reconvergence_driven_cut_impl; + using signal = aig_network::signal; + aig_network aig; const auto a = aig.create_pi(); const auto b = aig.create_pi(); @@ -52,21 +59,25 @@ TEST_CASE( "generate fanout-cuts for an AIG", "[cut_generation]" ) const auto f4 = aig.create_nand( f2, f3 ); aig.create_po( f4 ); + /* some ordered container */ using set_t = std::set>; - fanout_view fanout_aig{aig}; - fanout_aig.clear_visited(); - - /* helper functions for generating leaves */ - auto parents = [&]( const auto& p, unsigned size = 10u ){ - const auto parents = reconv_fanout_cut( reconv_cut_params{ size } )( fanout_aig, aig.get_node( p ) ); - return set_t( parents.begin(), parents.end() ); + /* helper functions for extracting leave sets */ + auto leaves = [&]( signal const& p, uint64_t size = 10u ){ + typename cuts_impl::parameters_type ps{size}; + typename cuts_impl::statistics_type st; + auto const leaves = cuts_impl( aig, ps, st ).run( { aig.get_node( p ) } ).first; + return set_t( std::begin( leaves ), std::end( leaves ) ); }; - CHECK( parents( f4 ) == set_t{ aig.get_node( f4 ) } ); - CHECK( parents( f3 ) == set_t{ aig.get_node( f4 ) } ); - CHECK( parents( f2 ) == set_t{ aig.get_node( f4 ) } ); - CHECK( parents( f1 ) == set_t{ aig.get_node( f4 ) } ); - CHECK( parents( b ) == set_t{ aig.get_node( f4 ) } ); - CHECK( parents( a ) == set_t{ aig.get_node( f4 ) } ); + CHECK( leaves( a ) == set_t{ aig.get_node( a ) } ); + CHECK( leaves( b ) == set_t{ aig.get_node( b ) } ); + CHECK( leaves( f1 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); + CHECK( leaves( f2 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); + CHECK( leaves( f3 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); + CHECK( leaves( f4 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); + + CHECK( leaves( f4, 1u ) == set_t{ aig.get_node( f4 ) } ); + CHECK( leaves( f4, 2u ) == set_t{aig.get_node( f2 ), aig.get_node( f3 )} ); + CHECK( leaves( f4, 3u ) == set_t{aig.get_node( a ), aig.get_node( b )} ); } diff --git a/test/algorithms/reconv_cut2.cpp b/test/algorithms/reconv_cut2.cpp deleted file mode 100644 index 5c0b31413..000000000 --- a/test/algorithms/reconv_cut2.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include - -#include -#include - -#include -#include -#include -#include - -using namespace mockturtle; - -TEST_CASE( "generate reconvergence-driven cuts for an AIG", "[cut_generation]" ) -{ - aig_network aig; - const auto a = aig.create_pi(); - const auto b = aig.create_pi(); - const auto f1 = aig.create_nand( a, b ); - const auto f2 = aig.create_nand( f1, a ); - const auto f3 = aig.create_nand( f1, b ); - const auto f4 = aig.create_nand( f2, f3 ); - aig.create_po( f4 ); - - using set_t = std::set>; - - fanout_view aig_fanout_view( aig ); - depth_view> aig_view( aig_fanout_view ); - cut_manager>> mgr( 6 ); - - auto leaves = [&]( const auto& s, uint32_t size = 1000u ){ - mgr.node_size_max = size; - const auto leaves = reconv_driven_cut( mgr, aig_view, aig.get_node( s ) ); - return set_t( leaves.begin(), leaves.end() ); - }; - - CHECK( leaves( a ) == set_t{} ); - CHECK( leaves( b ) == set_t{} ); - CHECK( leaves( f1 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); - CHECK( leaves( f2 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); - CHECK( leaves( f3 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); - CHECK( leaves( f4 ) == set_t{aig.get_node( a ), aig.get_node( b )} ); - CHECK( leaves( f4, 1u ) == set_t{} ); - CHECK( leaves( f4, 2u ) == set_t{aig.get_node( f2 ), aig.get_node( f3 )} ); - CHECK( leaves( f4, 3u ) == set_t{aig.get_node( a ), aig.get_node( b )} ); -} diff --git a/test/algorithms/resubstitution.cpp b/test/algorithms/resubstitution.cpp index 18d1e324c..f60852760 100644 --- a/test/algorithms/resubstitution.cpp +++ b/test/algorithms/resubstitution.cpp @@ -11,14 +11,14 @@ #include #include -#include - #include #include #include #include #include +#include + using namespace mockturtle; TEST_CASE( "Resubstitution of AIG", "[resubstitution]" ) diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index c5b6d3720..16a1706b4 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -28,7 +28,8 @@ TEST_CASE( "create window view on AIG", "[window_view]" ) fanout_ntk.clear_visited(); const auto pivot1 = aig.get_node( f3 ); - auto const& leaves1 = reconv_cut( reconv_cut_params{4} )( aig, { pivot1 } ); + + const auto leaves1 = reconvergence_driven_cut( aig, pivot1 ).first; window_view> win1( fanout_ntk, leaves1, { pivot1 }, false ); CHECK( is_network_type_v ); @@ -37,14 +38,14 @@ TEST_CASE( "create window view on AIG", "[window_view]" ) CHECK( win1.num_pos() == 3 ); // b, f1, f2 const auto pivot2 = aig.get_node( f2 ); - auto const& leaves2 = reconv_cut( reconv_cut_params{4} )( aig, { pivot2 } ); + const auto leaves2 = reconvergence_driven_cut( aig, pivot2 ).first; window_view> win2( fanout_ntk, leaves2, { pivot2 }, false ); CHECK( win2.size() == 5 ); CHECK( win2.num_pis() == 2 ); CHECK( win2.num_pos() == 3 ); // a, f1, f3 const auto pivot3 = aig.get_node( f1 ); - auto const& leaves3 = reconv_cut( reconv_cut_params{4} )( aig, { pivot3 } ); + const auto leaves3 = reconvergence_driven_cut( aig, pivot3 ).first; window_view> win3( fanout_ntk, leaves3, { pivot3 }, true ); CHECK( win3.size() == 7 ); CHECK( win3.num_pis() == 2 );