From 66b6eff25a1387271cc139b54c8deec660c2de50 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 30 Sep 2020 15:51:40 +0200 Subject: [PATCH 01/30] window_view. --- include/mockturtle/views/window_view.hpp | 237 ++++++++++++++++++++++- test/views/window_view.cpp | 187 ++++++++++++++++++ 2 files changed, 417 insertions(+), 7 deletions(-) diff --git a/include/mockturtle/views/window_view.hpp b/include/mockturtle/views/window_view.hpp index 3d7a61ebb..376b2537a 100644 --- a/include/mockturtle/views/window_view.hpp +++ b/include/mockturtle/views/window_view.hpp @@ -32,21 +32,244 @@ #pragma once +#include "../traits.hpp" +#include "../networks/detail/foreach.hpp" +#include "immutable_view.hpp" + #include +#include #include +#include #include #include -#include -#include - -#include "../traits.hpp" -#include "../networks/detail/foreach.hpp" -#include "immutable_view.hpp" namespace mockturtle { -/*! \brief Implements an isolated view on a window in a network. */ +/*! \brief Implements an isolated view on a window in a network. + * + * This view creates a network from a window in a large network. The + * window is specified by three parameters: + * 1.) `inputs` are the common support of all window nodes, they do + * not overlap with `gates` (i.e., the intersection of `inputs` and + * `gates` is the empty set). + * 2.) `gates` are the nodes in the window, supported by the + * `inputs` (i.e., `gates` are in the transitive fanout of the + * `inputs`, + * 3.) `outputs` are signals (regular or complemented nodes) + * pointing to nodes in `gates` or `inputs`. Not all fanouts + * of an output node are already part of the window. + * + * The second parameter `gates` has to be passed and is not + * automatically computed (for example in contrast to `cut_view`), + * because there are different strategies to construct a window from a + * support set. The outputs could be automatically computed. + * + * The window_view implements one new API method: + * 1.) `belongs_to_window`: takes a node as input and returns true + * if and only if this node is a constant, an input, or an inner + * node of the window + */ +template +class new_window_view : public immutable_view +{ +public: + using storage = typename Ntk::storage; + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +public: + explicit new_window_view( Ntk const& ntk, std::vector const& inputs, std::vector const& outputs, std::vector const& gates ) + : immutable_view( ntk ) + , _inputs( inputs ) + , _outputs( outputs ) + { + construct( inputs, gates ); + } + + explicit new_window_view( Ntk const& ntk, std::vector const& inputs, std::vector const& outputs, std::vector const& gates ) + : immutable_view( ntk ) + , _inputs( inputs ) + { + construct( inputs, gates ); + + /* convert output nodes to signals */ + std::transform( std::begin( outputs ), std::end( outputs ), std::back_inserter( _outputs ), + [this]( node const& n ){ + return this->make_signal( n ); + }); + } + +#pragma region Window + inline bool belongs_to_window( node const& n ) const + { + return std::find( std::begin( _nodes ), std::end( _nodes ), n ) != std::end( _nodes ); + } +#pragma endregion + +#pragma region Structural properties + inline uint32_t size() const + { + return static_cast( _nodes.size() ); + } + + inline uint32_t num_cis() const + { + return num_pis(); + } + + inline uint32_t num_cos() const + { + return num_pos(); + } + + inline uint32_t num_latches() const + { + return 0u; + } + + inline uint32_t num_pis() const + { + return static_cast( _inputs.size() ); + } + + inline uint32_t num_pos() const + { + return static_cast( _outputs.size() ); + } + + inline uint32_t num_registers() const + { + return 0u; + } + + inline uint32_t num_gates() const + { + return static_cast( _nodes.size() - _inputs.size() - 1u ); + } + + inline uint32_t node_to_index( node const& n ) const + { + return _node_to_index.at( n ); + } + + inline node index_to_node( uint32_t index ) const + { + return _nodes[index]; + } + + inline bool is_pi( node const& n ) const + { + return std::find( std::begin( _inputs ), std::end( _inputs ), n ) != std::end( _inputs ); + } + + inline bool is_ci( node const& n ) const + { + return is_pi( n ); + } + +#pragma endregion + +#pragma region Node and signal iterators + template + void foreach_pi( Fn&& fn ) const + { + detail::foreach_element( std::begin( _inputs ), std::end( _inputs ), fn ); + } + + template + void foreach_po( Fn&& fn ) const + { + detail::foreach_element( std::begin( _outputs ), std::end( _outputs ), fn ); + } + + template + void foreach_ci( Fn&& fn ) const + { + foreach_pi( fn ); + } + + template + void foreach_co( Fn&& fn ) const + { + foreach_po( fn ); + } + + template + void foreach_ro( Fn&& fn ) const + { + (void)fn; + } + + template + void foreach_ri( Fn&& fn ) const + { + (void)fn; + } + + template + void foreach_register( Fn&& fn ) const + { + (void)fn; + } + + template + void foreach_node( Fn&& fn ) const + { + detail::foreach_element( std::begin( _nodes ), std::end( _nodes ), fn ); + } + + template + void foreach_gate( Fn&& fn ) const + { + detail::foreach_element( std::begin( _nodes ) + 1u + _inputs.size(), std::end( _nodes ), fn ); + } + + template + void foreach_fanin( node const& n, Fn&& fn ) const + { + /* constants and inputs do not have fanins */ + if ( this->is_constant( n ) || + std::find( std::begin( _inputs ), std::end( _inputs ), n ) != std::end( _inputs ) ) + { + return; + } + + /* if it's not a window input, the node has to be a window node */ + assert( std::find( std::begin( _nodes ) + 1 + _inputs.size(), std::end( _nodes ), n ) != std::end( _nodes ) ); + immutable_view::foreach_fanin( n, fn ); + } +#pragma endregion + +protected: + void construct( std::vector const& inputs, std::vector const& gates ) + { + /* copy constant to nodes */ + _nodes.emplace_back( this->get_node( this->get_constant( false ) ) ); + + /* copy inputs to nodes */ + std::copy( std::begin( inputs ), std::end( inputs ), std::back_inserter( _nodes ) ); + + /* copy gates to nodes */ + std::copy( std::begin( gates ), std::end( gates ), std::back_inserter( _nodes ) ); + + /* create a mapping from node id (index in the original network) to window index */ + for ( uint32_t index = 0; index < _nodes.size(); ++index ) + { + _node_to_index[_nodes.at( index )] = index; + } + } + +protected: + std::vector _inputs; + std::vector _outputs; + std::vector _nodes; + std::unordered_map _node_to_index; +}; /* new_window_view */ + +/*! \brief Implements an isolated view on a window in a network. + * + */ template class window_view : public immutable_view { diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 16a1706b4..3cba19d32 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -8,6 +8,193 @@ using namespace mockturtle; +template +std::vector collect_fanin_nodes( Ntk const& ntk, typename Ntk::node const& n ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + std::vector fanin_nodes; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + fanin_nodes.emplace_back( ntk.get_node( fi ) ); + }); + return fanin_nodes; +} + +/*! \brief Ensure that all outputs and fanins belong to the window */ +template +bool window_is_well_formed( Ntk const& ntk ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + bool all_fanins_belong_to_window = true; + ntk.foreach_node( [&]( node const& n ){ + ntk.foreach_fanin( n, [&]( signal const& fi ){ + if ( !ntk.belongs_to_window( ntk.get_node( fi ) ) ) + { + all_fanins_belong_to_window = false; + return false; /* terminate */ + } + return true; /* next */ + }); + + /* check if property is already violated */ + if ( !all_fanins_belong_to_window ) + { + return false; /* terminate */ + } + return true; /* next */ + }); + + bool all_outputs_belong_to_window = true; + ntk.foreach_po( [&]( signal const& o ){ + if ( !ntk.belongs_to_window( ntk.get_node( o ) ) ) + { + all_outputs_belong_to_window = false; + return false; /* terminate */ + } + return true; /* next */ + }); + + return all_fanins_belong_to_window && + all_outputs_belong_to_window; +} + +TEST_CASE( "create new window view on AIG", "[window_view]" ) +{ + 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( a, f1 ); + const auto f3 = aig.create_nand( b, f1 ); + const auto f4 = aig.create_nand( f2, f3 ); + aig.create_po( f4 ); + + CHECK( aig.size() == 7 ); + CHECK( aig.num_pis() == 2 ); + CHECK( aig.num_pos() == 1 ); + CHECK( aig.num_gates() == 4 ); + + /* make a window */ + { + new_window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f3 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f3 ) } ); + CHECK( view.size() == 5 ); + CHECK( view.num_gates() == 2 ); + CHECK( view.num_pis() == 2 ); + CHECK( view.num_pos() == 1 ); + CHECK( view.num_cis() == 2 ); + CHECK( view.num_cos() == 1 ); + + CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f2 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + + CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f3 ) ).size() == 2 ); + CHECK( window_is_well_formed( view ) ); + } + + { + new_window_view view( aig, + /* inputs = */ { aig.get_node( f1 ), aig.get_node( b ) }, + /* outputs = */ { f3 }, + /* nodes = */ { aig.get_node( f3 ) } ); + CHECK( view.size() == 4 ); + CHECK( view.num_gates() == 1 ); + CHECK( view.num_pis() == 2 ); + CHECK( view.num_pos() == 1 ); + CHECK( view.num_cis() == 2 ); + CHECK( view.num_cos() == 1 ); + + CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f2 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + + CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 0 ); + CHECK( collect_fanin_nodes( view, view.get_node( f3 ) ).size() == 2 ); + CHECK( window_is_well_formed( view ) ); + } + + { + new_window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f2 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ) } ); + + CHECK( view.size() == 5 ); + CHECK( view.num_gates() == 2 ); + CHECK( view.num_pis() == 2 ); + CHECK( view.num_pos() == 1 ); + CHECK( view.num_cis() == 2 ); + CHECK( view.num_cos() == 1 ); + + CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f2 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + + CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f2 ) ).size() == 2 ); + CHECK( window_is_well_formed( view ) ); + } + + { + new_window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f4 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 ) } ); + + CHECK( view.size() == 7 ); + CHECK( view.num_gates() == 4 ); + CHECK( view.num_pis() == 2 ); + CHECK( view.num_pos() == 1 ); + CHECK( view.num_cis() == 2 ); + CHECK( view.num_cos() == 1 ); + + CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f2 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f4 ) ) ); + + CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f2 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f3 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f4 ) ).size() == 2 ); + CHECK( window_is_well_formed( view ) ); + } + + { + new_window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f2, f3 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ) } ); + + CHECK( view.size() == 6 ); + CHECK( view.num_gates() == 3 ); + CHECK( view.num_pis() == 2 ); + CHECK( view.num_pos() == 2 ); + CHECK( view.num_cis() == 2 ); + CHECK( view.num_cos() == 2 ); + + CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f2 ) ) ); + CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + + CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f2 ) ).size() == 2 ); + CHECK( collect_fanin_nodes( view, view.get_node( f3 ) ).size() == 2 ); + CHECK( window_is_well_formed( view ) ); + } +} + TEST_CASE( "create window view on AIG", "[window_view]" ) { aig_network aig; From 3643264c8147f2db07f5ca88e54993909635541e Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 1 Oct 2020 17:13:54 +0200 Subject: [PATCH 02/30] identify output signals using reference counting. --- include/mockturtle/views/window_view.hpp | 80 ++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/include/mockturtle/views/window_view.hpp b/include/mockturtle/views/window_view.hpp index 376b2537a..793083095 100644 --- a/include/mockturtle/views/window_view.hpp +++ b/include/mockturtle/views/window_view.hpp @@ -46,6 +46,86 @@ namespace mockturtle { +/*! \brief Identify outputs using reference counting + * + * Identify outputs using a reference counting approach. The + * algorithm counts the references of the fanins of all nodes and + * compares them with the fanout_sizes of the respective nodes. If + * reference count and fanout_size do not match, then the node is + * references outside of the node set and the respective is identified + * as an output. + * + * \param inputs Inputs of a window + * \param nodes Inner nodes of a window (i.e., the intersection of + * inputs and nodes is assumed to be empty) + * \param refs Reference counters (in the size of the network and + * initialized to 0) + * \return Output signals of the window + */ +template +std::vector find_outputs( Ntk const& ntk, + std::vector const& inputs, + std::vector const& nodes, + std::vector& refs ) +{ + using signal = typename Ntk::signal; + std::vector outputs; + + /* create a new traversal ID */ + ntk.incr_trav_id(); + + /* mark the inputs visited */ + for ( auto const& i : inputs ) + { + ntk.set_visited( i, ntk.trav_id() ); + } + + /* reference fanins of nodes */ + for ( auto const& n : nodes ) + { + if ( ntk.visited( n ) == ntk.trav_id() ) + { + continue; + } + + assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); + ntk.foreach_fanin( n, [&]( signal const& fi ){ + refs[ntk.get_node( fi )] += 1; + }); + } + + /* if the fanout_size of a node does not match the reference count, + the node has fanout outside of the window is an output */ + for ( const auto& n : nodes ) + { + if ( ntk.visited( n ) == ntk.trav_id() ) + { + continue; + } + + if ( ntk.fanout_size( n ) != refs[n] ) + { + outputs.emplace_back( ntk.make_signal( n ) ); + } + } + + /* dereference fanins of nodes */ + for ( auto const& n : nodes ) + { + if ( ntk.visited( n ) == ntk.trav_id() ) + { + continue; + } + + assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); + ntk.foreach_fanin( n, [&]( signal const& fi ){ + refs[ntk.get_node( fi )] -= 1; + }); + } + + return outputs; +} + /*! \brief Implements an isolated view on a window in a network. * * This view creates a network from a window in a large network. The From 3cdfe466263e5116df26d36172203b8a03c232d2 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Sun, 4 Oct 2020 18:41:03 +0200 Subject: [PATCH 03/30] window_view. --- include/mockturtle/algorithms/dont_cares.hpp | 6 +- include/mockturtle/utils/window_utils.hpp | 204 ++++++++++++ include/mockturtle/views/window_view.hpp | 310 +------------------ test/views/window_view.cpp | 96 +++--- 4 files changed, 254 insertions(+), 362 deletions(-) create mode 100644 include/mockturtle/utils/window_utils.hpp diff --git a/include/mockturtle/algorithms/dont_cares.hpp b/include/mockturtle/algorithms/dont_cares.hpp index d20c1c69e..1dd068ea0 100644 --- a/include/mockturtle/algorithms/dont_cares.hpp +++ b/include/mockturtle/algorithms/dont_cares.hpp @@ -75,7 +75,8 @@ kitty::dynamic_truth_table satisfiability_dont_cares( Ntk const& ntk, std::vecto fanout_view fanout_ntk{ntk}; fanout_ntk.clear_visited(); - window_view> window_ntk{fanout_ntk, extended_leaves, leaves, false}; + std::vector> gates{collect_nodes( ntk, extended_leaves, leaves )}; + window_view> window_ntk{fanout_ntk, extended_leaves, leaves, gates}; default_simulator sim( window_ntk.num_pis() ); const auto tts = simulate_nodes( window_ntk, sim ); @@ -111,7 +112,8 @@ kitty::dynamic_truth_table observability_dont_cares( Ntk const& ntk, node c fanout_view fanout_ntk{ntk}; fanout_ntk.clear_visited(); - window_view> window_ntk{fanout_ntk, leaves, roots, false}; + std::vector> gates{collect_nodes( ntk, leaves, roots )}; + window_view> window_ntk{fanout_ntk, leaves, roots, gates}; default_simulator sim( window_ntk.num_pis() ); unordered_node_map node_to_value0( ntk ); diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp new file mode 100644 index 000000000..0e56b748b --- /dev/null +++ b/include/mockturtle/utils/window_utils.hpp @@ -0,0 +1,204 @@ +/* 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 window_utils.hpp + \brief Utils to structurally collect node sets + + \author Heinz Riener +*/ + +namespace mockturtle +{ + +namespace detail +{ + +template +inline void collect_nodes_recur( Ntk const& ntk, typename Ntk::node const& n, std::vector& nodes ) +{ + using signal = typename Ntk::signal; + + if ( ntk.visited( n ) == ntk.trav_id() ) + { + return; + } + ntk.set_visited( n, ntk.trav_id() ); + + ntk.foreach_fanin( n, [&]( signal const& fi ){ + collect_nodes_recur( ntk, ntk.get_node( fi ), nodes ); + }); + nodes.push_back( n ); +} + +} /* namespace detail */ + +/*! \brief Collect nodes in between of two node sets + * + * \param ntk A network + * \param inputs A node set + * \param outputs A signal set + * \return Nodes enclosed by inputs and outputs + * + * The output set has to be chosen in a way such that every path from + * PIs to outputs passes through at least one input. + */ +template>> +inline std::vector collect_nodes( Ntk const& ntk, + std::vector const& inputs, + std::vector const& outputs ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + /* convert output signals to nodes */ + std::vector _outputs; + std::transform( std::begin( outputs ), std::end( outputs ), std::back_inserter( _outputs ), + [&ntk]( signal const& s ){ + return ntk.get_node( s ); + }); + return collect_nodes( ntk, inputs, _outputs ); +} + +/*! \brief Collect nodes in between of two node sets + * + * \param ntk A network + * \param inputs A node set + * \param outputs A node set + * \return Nodes enclosed by inputs and outputs + * + * The output set has to be chosen in a way such that every path from + * PIs to outputs passes through at least one input. + */ +template +inline std::vector collect_nodes( Ntk const& ntk, + std::vector const& inputs, + std::vector const& outputs ) +{ + using node = typename Ntk::node; + + /* create a new traversal ID */ + ntk.incr_trav_id(); + + /* mark inputs visited */ + for ( auto const& i : inputs ) + { + if ( ntk.visited( i ) == ntk.trav_id() ) + { + continue; + } + ntk.set_visited( i, ntk.trav_id() ); + } + + /* recursively collect all nodes in between inputs and outputs */ + std::vector nodes; + for ( auto const& o : outputs ) + { + detail::collect_nodes_recur( ntk, o, nodes ); + } + return nodes; +} + +/*! \brief Identify outputs using reference counting + * + * Identify outputs using a reference counting approach. The + * algorithm counts the references of the fanins of all nodes and + * compares them with the fanout_sizes of the respective nodes. If + * reference count and fanout_size do not match, then the node is + * references outside of the node set and the respective is identified + * as an output. + * + * \param inputs Inputs of a window + * \param nodes Inner nodes of a window (i.e., the intersection of + * inputs and nodes is assumed to be empty) + * \param refs Reference counters (in the size of the network and + * initialized to 0) + * \return Output signals of the window + */ +template +inline std::vector find_outputs( Ntk const& ntk, + std::vector const& inputs, + std::vector const& nodes, + std::vector& refs ) +{ + using signal = typename Ntk::signal; + std::vector outputs; + + /* create a new traversal ID */ + ntk.incr_trav_id(); + + /* mark the inputs visited */ + for ( auto const& i : inputs ) + { + ntk.set_visited( i, ntk.trav_id() ); + } + + /* reference fanins of nodes */ + for ( auto const& n : nodes ) + { + if ( ntk.visited( n ) == ntk.trav_id() ) + { + continue; + } + + assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); + ntk.foreach_fanin( n, [&]( signal const& fi ){ + refs[ntk.get_node( fi )] += 1; + }); + } + + /* if the fanout_size of a node does not match the reference count, + the node has fanout outside of the window is an output */ + for ( const auto& n : nodes ) + { + if ( ntk.visited( n ) == ntk.trav_id() ) + { + continue; + } + + if ( ntk.fanout_size( n ) != refs[n] ) + { + outputs.emplace_back( ntk.make_signal( n ) ); + } + } + + /* dereference fanins of nodes */ + for ( auto const& n : nodes ) + { + if ( ntk.visited( n ) == ntk.trav_id() ) + { + continue; + } + + assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); + ntk.foreach_fanin( n, [&]( signal const& fi ){ + refs[ntk.get_node( fi )] -= 1; + }); + } + + return outputs; +} + +} /* namespace mockturtle */ diff --git a/include/mockturtle/views/window_view.hpp b/include/mockturtle/views/window_view.hpp index 793083095..8ff10c9c9 100644 --- a/include/mockturtle/views/window_view.hpp +++ b/include/mockturtle/views/window_view.hpp @@ -34,8 +34,8 @@ #include "../traits.hpp" #include "../networks/detail/foreach.hpp" +#include "../utils/window_utils.hpp" #include "immutable_view.hpp" - #include #include #include @@ -46,86 +46,6 @@ namespace mockturtle { -/*! \brief Identify outputs using reference counting - * - * Identify outputs using a reference counting approach. The - * algorithm counts the references of the fanins of all nodes and - * compares them with the fanout_sizes of the respective nodes. If - * reference count and fanout_size do not match, then the node is - * references outside of the node set and the respective is identified - * as an output. - * - * \param inputs Inputs of a window - * \param nodes Inner nodes of a window (i.e., the intersection of - * inputs and nodes is assumed to be empty) - * \param refs Reference counters (in the size of the network and - * initialized to 0) - * \return Output signals of the window - */ -template -std::vector find_outputs( Ntk const& ntk, - std::vector const& inputs, - std::vector const& nodes, - std::vector& refs ) -{ - using signal = typename Ntk::signal; - std::vector outputs; - - /* create a new traversal ID */ - ntk.incr_trav_id(); - - /* mark the inputs visited */ - for ( auto const& i : inputs ) - { - ntk.set_visited( i, ntk.trav_id() ); - } - - /* reference fanins of nodes */ - for ( auto const& n : nodes ) - { - if ( ntk.visited( n ) == ntk.trav_id() ) - { - continue; - } - - assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); - ntk.foreach_fanin( n, [&]( signal const& fi ){ - refs[ntk.get_node( fi )] += 1; - }); - } - - /* if the fanout_size of a node does not match the reference count, - the node has fanout outside of the window is an output */ - for ( const auto& n : nodes ) - { - if ( ntk.visited( n ) == ntk.trav_id() ) - { - continue; - } - - if ( ntk.fanout_size( n ) != refs[n] ) - { - outputs.emplace_back( ntk.make_signal( n ) ); - } - } - - /* dereference fanins of nodes */ - for ( auto const& n : nodes ) - { - if ( ntk.visited( n ) == ntk.trav_id() ) - { - continue; - } - - assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); - ntk.foreach_fanin( n, [&]( signal const& fi ){ - refs[ntk.get_node( fi )] -= 1; - }); - } - - return outputs; -} - /*! \brief Implements an isolated view on a window in a network. * * This view creates a network from a window in a large network. The @@ -151,7 +71,7 @@ std::vector find_outputs( Ntk const& ntk, * node of the window */ template -class new_window_view : public immutable_view +class window_view : public immutable_view { public: using storage = typename Ntk::storage; @@ -159,7 +79,8 @@ class new_window_view : public immutable_view using signal = typename Ntk::signal; public: - explicit new_window_view( Ntk const& ntk, std::vector const& inputs, std::vector const& outputs, std::vector const& gates ) + template>> + explicit window_view( Ntk const& ntk, std::vector const& inputs, std::vector const& outputs, std::vector const& gates ) : immutable_view( ntk ) , _inputs( inputs ) , _outputs( outputs ) @@ -167,7 +88,7 @@ class new_window_view : public immutable_view construct( inputs, gates ); } - explicit new_window_view( Ntk const& ntk, std::vector const& inputs, std::vector const& outputs, std::vector const& gates ) + explicit window_view( Ntk const& ntk, std::vector const& inputs, std::vector const& outputs, std::vector const& gates ) : immutable_view( ntk ) , _inputs( inputs ) { @@ -248,6 +169,7 @@ class new_window_view : public immutable_view return is_pi( n ); } + inline uint32_t fanout_size( node const& n ) const = delete; #pragma endregion #pragma region Node and signal iterators @@ -345,224 +267,6 @@ class new_window_view : public immutable_view std::vector _outputs; std::vector _nodes; std::unordered_map _node_to_index; -}; /* new_window_view */ - -/*! \brief Implements an isolated view on a window in a network. - * - */ -template -class window_view : public immutable_view -{ -public: - using storage = typename Ntk::storage; - using node = typename Ntk::node; - using signal = typename Ntk::signal; - -public: - explicit window_view( Ntk const& ntk, std::vector const& leaves, std::vector const& pivots, bool auto_extend = true ) - : immutable_view( ntk ) - { - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_set_visited_v, "Ntk does not implement the set_visited method" ); - static_assert( has_visited_v, "Ntk does not implement the visited method" ); - static_assert( has_get_node_v, "Ntk does not implement the get_node method" ); - static_assert( has_get_constant_v, "Ntk does not implement the get_constant method" ); - static_assert( has_is_constant_v, "Ntk does not implement the is_constant method" ); - static_assert( has_make_signal_v, "Ntk does not implement the make_signal method" ); - static_assert( has_foreach_fanout_v, "Ntk does not implement the foreach_fanout method" ); - - this->incr_trav_id(); - - /* constants */ - add_node( this->get_node( this->get_constant( false ) ) ); - this->set_visited( this->get_node( this->get_constant( false ) ), this->trav_id() ); - if ( this->get_node( this->get_constant( true ) ) != this->get_node( this->get_constant( false ) ) ) - { - add_node( this->get_node( this->get_constant( true ) ) ); - this->set_visited( this->get_node( this->get_constant( true ) ), this->trav_id() ); - ++_num_constants; - } - - /* primary inputs */ - for ( auto const& leaf : leaves ) - { - if ( this->visited( leaf ) == this->trav_id() ) - continue; - this->set_visited( leaf, this->trav_id() ); - - add_node( leaf ); - ++_num_leaves; - } - - for ( auto const& p : pivots ) - { - traverse( p ); - } - - if ( auto_extend ) - { - extend( ntk ); - } - - add_roots( ntk ); - } - - inline auto size() const { return _nodes.size(); } - inline auto num_pis() const { return _num_leaves; } - inline auto num_pos() const { return _roots.size(); } - inline auto num_gates() const { return _nodes.size() - _num_leaves - _num_constants; } - - inline auto node_to_index( const node& n ) const { return _node_to_index.at( n ); } - inline auto index_to_node( uint32_t index ) const { return _nodes[index]; } - - inline bool is_pi( node const& pi ) const - { - const auto beg = _nodes.begin() + _num_constants; - return std::find( beg, beg + _num_leaves, pi ) != beg + _num_leaves; - } - - template - void foreach_pi( Fn&& fn ) const - { - detail::foreach_element( _nodes.begin() + _num_constants, _nodes.begin() + _num_constants + _num_leaves, fn ); - } - - template - void foreach_po( Fn&& fn ) const - { - detail::foreach_element( _roots.begin(), _roots.end(), fn ); - } - - template - void foreach_node( Fn&& fn ) const - { - detail::foreach_element( _nodes.begin(), _nodes.end(), fn ); - } - - template - void foreach_gate( Fn&& fn ) const - { - detail::foreach_element( _nodes.begin() + _num_constants + _num_leaves, _nodes.end(), fn ); - } - - uint32_t fanout_size( node const& n ) const - { - return _fanout_size.at( node_to_index( n ) ); - } - -private: - void add_node( node const& n ) - { - _node_to_index[n] = static_cast( _nodes.size() ); - _nodes.push_back( n ); - - auto fanout_counter = 0; - this->foreach_fanin( n, [&]( const auto& f ) { - if ( std::find( _nodes.begin(), _nodes.end(), this->get_node( f ) ) != _nodes.end() ) - { - fanout_counter++; - } - }); - _fanout_size.push_back( fanout_counter ); - } - - void traverse( node const& n ) - { - if ( this->visited( n ) == this->trav_id() ) - return; - this->set_visited( n, this->trav_id() ); - - this->foreach_fanin( n, [&]( const auto& f ) { - traverse( this->get_node( f ) ); - } ); - - add_node( n ); - } - - void extend( Ntk const& ntk ) - { - std::set new_nodes; - do - { - new_nodes.clear(); - for ( const auto& n : _nodes ) - { - ntk.foreach_fanout( n, [&]( auto const& p ){ - /* skip node if it is already in _nodes */ - if ( std::find( _nodes.begin(), _nodes.end(), p ) != _nodes.end() ) return; - - auto all_children_in_nodes = true; - ntk.foreach_fanin( p, [&]( auto const& s ){ - auto const& child = ntk.get_node( s ); - if ( std::find( _nodes.begin(), _nodes.end(), child ) == _nodes.end() ) - { - all_children_in_nodes = false; - return false; - } - return true; - }); - - if ( all_children_in_nodes ) - { - assert( p != 0 ); - assert( !is_pi( p ) ); - new_nodes.insert( p ); - } - }); - } - - for ( const auto& n : new_nodes ) - { - add_node( n ); - } - } while ( !new_nodes.empty() ); - } - - void add_roots( Ntk const& ntk ) - { - /* compute po nodes */ - std::vector pos; - ntk.foreach_po( [&]( auto const& s ){ - pos.push_back( ntk.get_node( s ) ); - }); - - /* compute window outputs */ - for ( const auto& n : _nodes ) - { - // if ( ntk.is_constant( n ) || ntk.is_pi( n ) ) continue; - - if ( std::find( pos.begin(), pos.end(), n ) != pos.end() ) - { - auto s = this->make_signal( n ); - if ( std::find( _roots.begin(), _roots.end(), s ) == _roots.end() ) - { - _roots.push_back( s ); - } - continue; - } - - ntk.foreach_fanout( n, [&]( auto const& p ){ - if ( std::find( _nodes.begin(), _nodes.end(), p ) == _nodes.end() ) - { - auto s = this->make_signal( n ); - if ( std::find( _roots.begin(), _roots.end(), s ) == _roots.end() ) - { - _roots.push_back( s ); - return false; - } - } - return true; - }); - } - } - -public: - unsigned _num_constants{1}; - unsigned _num_leaves{0}; - std::vector _nodes; - std::unordered_map _node_to_index; - std::vector _roots; - std::vector _fanout_size; -}; +}; /* window_view */ } /* namespace mockturtle */ diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 3cba19d32..fdfb19878 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -79,10 +79,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) /* make a window */ { - new_window_view view( aig, - /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, - /* outputs = */ { f3 }, - /* nodes = */ { aig.get_node( f1 ), aig.get_node( f3 ) } ); + window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f3 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f3 ) } ); CHECK( view.size() == 5 ); CHECK( view.num_gates() == 2 ); CHECK( view.num_pis() == 2 ); @@ -101,10 +101,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) } { - new_window_view view( aig, - /* inputs = */ { aig.get_node( f1 ), aig.get_node( b ) }, - /* outputs = */ { f3 }, - /* nodes = */ { aig.get_node( f3 ) } ); + window_view view( aig, + /* inputs = */ { aig.get_node( f1 ), aig.get_node( b ) }, + /* outputs = */ { f3 }, + /* nodes = */ { aig.get_node( f3 ) } ); CHECK( view.size() == 4 ); CHECK( view.num_gates() == 1 ); CHECK( view.num_pis() == 2 ); @@ -123,10 +123,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) } { - new_window_view view( aig, - /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, - /* outputs = */ { f2 }, - /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ) } ); + window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f2 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ) } ); CHECK( view.size() == 5 ); CHECK( view.num_gates() == 2 ); @@ -146,10 +146,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) } { - new_window_view view( aig, - /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, - /* outputs = */ { f4 }, - /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 ) } ); + window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f4 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 ) } ); CHECK( view.size() == 7 ); CHECK( view.num_gates() == 4 ); @@ -171,10 +171,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) } { - new_window_view view( aig, - /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, - /* outputs = */ { f2, f3 }, - /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ) } ); + window_view view( aig, + /* inputs = */ { aig.get_node( a ), aig.get_node( b ) }, + /* outputs = */ { f2, f3 }, + /* nodes = */ { aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ) } ); CHECK( view.size() == 6 ); CHECK( view.num_gates() == 3 ); @@ -195,46 +195,28 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) } } -TEST_CASE( "create window view on AIG", "[window_view]" ) +TEST_CASE( "collect nodes", "[window_view]" ) { 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( a, f1 ); - const auto f3 = aig.create_nand( b, f1 ); - const auto f4 = aig.create_nand( f2, f3 ); + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + auto const d = aig.create_pi(); + auto const f1 = aig.create_xor( a, b ); + auto const f2 = aig.create_xor( c, d ); + auto const f3 = aig.create_xor( f1, f2 ); + auto const f4 = aig.create_and( f1, f2 ); + aig.create_po( f3 ); aig.create_po( f4 ); - CHECK( aig.size() == 7 ); - CHECK( aig.num_pis() == 2 ); - CHECK( aig.num_pos() == 1 ); - CHECK( aig.num_gates() == 4 ); - - fanout_view fanout_ntk( aig ); - fanout_ntk.clear_visited(); - - const auto pivot1 = aig.get_node( f3 ); + using node = typename aig_network::node; + using signal = typename aig_network::signal; + + std::vector input_boundary{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; + std::vector output_boundary{f3, f4}; - const auto leaves1 = reconvergence_driven_cut( aig, pivot1 ).first; - window_view> win1( fanout_ntk, leaves1, { pivot1 }, false ); - - CHECK( is_network_type_v ); - CHECK( win1.size() == 5 ); - CHECK( win1.num_pis() == 2 ); - CHECK( win1.num_pos() == 3 ); // b, f1, f2 - - const auto pivot2 = aig.get_node( f2 ); - 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 ); - 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 ); - CHECK( win3.num_pos() == 1 ); // f4 + std::vector const nodes{collect_nodes( aig, input_boundary, output_boundary )}; + aig.foreach_gate( [&]( node const& n ){ + CHECK( std::find( std::begin( nodes ), std::end( nodes ), n ) != std::end( nodes ) ); + }); } From 2ed9b32b5c3e14ec073c98e1abd061a79bbdf495 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Sun, 4 Oct 2020 21:48:27 +0200 Subject: [PATCH 04/30] window_view. --- include/mockturtle/utils/window_utils.hpp | 161 +++++++++++++++++++++- test/views/window_view.cpp | 41 +++++- 2 files changed, 194 insertions(+), 8 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 0e56b748b..7bda13397 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -25,11 +25,16 @@ /*! \file window_utils.hpp - \brief Utils to structurally collect node sets + \brief Utilities to collect small-scale sets of nodes \author Heinz Riener */ +#include +#include +#include +#include + namespace mockturtle { @@ -64,6 +69,14 @@ inline void collect_nodes_recur( Ntk const& ntk, typename Ntk::node const& n, st * * The output set has to be chosen in a way such that every path from * PIs to outputs passes through at least one input. + * + * **Required network functions:** + * - `foreach_fanin` + * - `get_node` + * - `incr_trav_id` + * - `set_visited` + * - `trav_id` + * - `visited` */ template>> inline std::vector collect_nodes( Ntk const& ntk, @@ -91,6 +104,14 @@ inline std::vector collect_nodes( Ntk const& ntk, * * The output set has to be chosen in a way such that every path from * PIs to outputs passes through at least one input. + * + * **Required network functions:** + * - `foreach_fanin` + * - `get_node` + * - `incr_trav_id` + * - `set_visited` + * - `trav_id` + * - `visited` */ template inline std::vector collect_nodes( Ntk const& ntk, @@ -130,12 +151,25 @@ inline std::vector collect_nodes( Ntk const& ntk, * references outside of the node set and the respective is identified * as an output. * + * \param ntk A network * \param inputs Inputs of a window * \param nodes Inner nodes of a window (i.e., the intersection of * inputs and nodes is assumed to be empty) * \param refs Reference counters (in the size of the network and * initialized to 0) * \return Output signals of the window + * + * **Required network functions:** + * - `fanout_size` + * - `foreach_fanin` + * - `get_node` + * - `incr_trav_id` + * - `is_ci` + * - `is_constant` + * - `make_signal` + * - `set_visited` + * - `trav_id` + * - `visited` */ template inline std::vector find_outputs( Ntk const& ntk, @@ -163,7 +197,7 @@ inline std::vector find_outputs( Ntk const& ntk, continue; } - assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); + assert( !ntk.is_constant( n ) && !ntk.is_ci( n ) ); ntk.foreach_fanin( n, [&]( signal const& fi ){ refs[ntk.get_node( fi )] += 1; }); @@ -192,7 +226,7 @@ inline std::vector find_outputs( Ntk const& ntk, continue; } - assert( !ntk.is_constant( n ) && !ntk.is_pi( n ) ); + assert( !ntk.is_constant( n ) && !ntk.is_ci( n ) ); ntk.foreach_fanin( n, [&]( signal const& fi ){ refs[ntk.get_node( fi )] -= 1; }); @@ -201,4 +235,125 @@ inline std::vector find_outputs( Ntk const& ntk, return outputs; } +/*! \brief Expand a nodes towards TFO + * + * Iteratively expands the inner nodes of the window with those + * fanouts that are supported by the window until a fixed-point is + * reached. + * + * \param ntk A network + * \param inputs Input nodes of a window + * \param nodes Inner nodes of a window + * + * **Required network functions:** + * - `foreach_fanin` + * - `foreach_fanout` + * - `get_node` + * - `incr_trav_id` + * - `is_ci` + * - `set_visited` + * - `trav_id` + * - `visited` + */ +template +void expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + auto explore_fanouts = [&]( Ntk const& ntk, node const& n, std::set& result ){ + ntk.foreach_fanout( n, [&]( node const& fo, uint64_t index ){ + /* only look at the first few fanouts */ + if ( index > 5 ) + { + return false; + } + /* skip all nodes that are already in nodex */ + if ( ntk.visited( fo ) == ntk.trav_id() ) + { + return true; + } + result.insert( fo ); + return true; + }); + }; + + /* create a new traversal ID */ + ntk.incr_trav_id(); + + /* mark the inputs visited */ + for ( auto const& i : inputs ) + { + ntk.set_visited( i, ntk.trav_id() ); + } + /* mark the nodes visited */ + for ( const auto& n : nodes ) + { + ntk.set_visited( n, ntk.trav_id() ); + } + + /* collect all nodes that have fanouts not yet contained in nodes */ + std::set eps; + for ( const auto& n : inputs ) + { + explore_fanouts( ntk, n, eps ); + } + for ( const auto& n : nodes ) + { + explore_fanouts( ntk, n, eps ); + } + + bool changed = true; + std::set new_eps; + while ( changed ) + { + new_eps.clear(); + changed = false; + + auto it = std::begin( eps ); + while ( it != std::end( eps ) ) + { + node const ep = *it; + if ( ntk.visited( ep ) == ntk.trav_id() ) + { + it = eps.erase( it ); + continue; + } + + bool all_children_belong_to_window = true; + ntk.foreach_fanin( ep, [&]( signal const& fi ){ + node const child = ntk.get_node( fi ); + if ( ntk.visited( child ) != ntk.trav_id() ) + { + all_children_belong_to_window = false; + return false; + } + return true; + }); + + if ( all_children_belong_to_window ) + { + assert( ep != 0 ); + assert( !ntk.is_ci( ep ) ); + nodes.emplace_back( ep ); + ntk.set_visited( ep, ntk.trav_id() ); + it = eps.erase( it ); + + explore_fanouts( ntk, ep, new_eps ); + } + + if ( it != std::end( eps ) ) + { + ++it; + } + } + + if ( !new_eps.empty() ) + { + eps.insert( std::begin( new_eps ), std::end( new_eps ) ); + changed = true; + } + } +} + } /* namespace mockturtle */ diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index fdfb19878..aca29d1cd 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -211,12 +211,43 @@ TEST_CASE( "collect nodes", "[window_view]" ) using node = typename aig_network::node; using signal = typename aig_network::signal; - - std::vector input_boundary{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; - std::vector output_boundary{f3, f4}; - std::vector const nodes{collect_nodes( aig, input_boundary, output_boundary )}; + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; + std::vector outputs{f3, f4}; + std::vector const gates{collect_nodes( aig, inputs, outputs )}; + + CHECK( gates.size() == aig.num_gates() ); + aig.foreach_gate( [&]( node const& n ){ + CHECK( std::find( std::begin( gates ), std::end( gates ), n ) != std::end( gates ) ); + }); +} + +TEST_CASE( "expand towards tfo", "[window_view]" ) +{ + aig_network aig; + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + auto const d = aig.create_pi(); + auto const f1 = aig.create_xor( a, b ); + auto const f2 = aig.create_xor( c, d ); + auto const f3 = aig.create_xor( f1, f2 ); + auto const f4 = aig.create_and( f1, f2 ); + aig.create_po( f3 ); + aig.create_po( f4 ); + + using node = typename aig_network::node; + using signal = typename aig_network::signal; + + fanout_view faig( aig ); + + std::vector inputs{faig.get_node( a ), faig.get_node( b ), faig.get_node( c ), faig.get_node( d )}; + std::vector outputs{f1}; + std::vector gates{collect_nodes( faig, inputs, outputs )}; + expand_towards_tfo( faig, inputs, gates ); + + CHECK( gates.size() == aig.num_gates() ); aig.foreach_gate( [&]( node const& n ){ - CHECK( std::find( std::begin( nodes ), std::end( nodes ), n ) != std::end( nodes ) ); + CHECK( std::find( std::begin( gates ), std::end( gates ), n ) != std::end( gates ) ); }); } From 56abcd6b6a64203da7caac47bac6dd6321faa584 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Sun, 4 Oct 2020 22:40:03 +0200 Subject: [PATCH 05/30] `belongs_to`. --- include/mockturtle/views/window_view.hpp | 18 ++++++---- test/views/window_view.cpp | 44 ++++++++++++------------ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/include/mockturtle/views/window_view.hpp b/include/mockturtle/views/window_view.hpp index 8ff10c9c9..b7274d49f 100644 --- a/include/mockturtle/views/window_view.hpp +++ b/include/mockturtle/views/window_view.hpp @@ -66,9 +66,9 @@ namespace mockturtle * support set. The outputs could be automatically computed. * * The window_view implements one new API method: - * 1.) `belongs_to_window`: takes a node as input and returns true - * if and only if this node is a constant, an input, or an inner - * node of the window + * 1.) `belongs_to`: takes a node as input and returns true if and + * only if this node is a constant, an input, or an inner node + * of the window */ template class window_view : public immutable_view @@ -102,7 +102,13 @@ class window_view : public immutable_view } #pragma region Window - inline bool belongs_to_window( node const& n ) const + template>> + inline bool belongs_to( signal const& s ) const + { + return std::find( std::begin( _nodes ), std::end( _nodes ), get_node( s ) ) != std::end( _nodes ); + } + + inline bool belongs_to( node const& n ) const { return std::find( std::begin( _nodes ), std::end( _nodes ), n ) != std::end( _nodes ); } @@ -149,6 +155,8 @@ class window_view : public immutable_view return static_cast( _nodes.size() - _inputs.size() - 1u ); } + inline uint32_t fanout_size( node const& n ) const = delete; + inline uint32_t node_to_index( node const& n ) const { return _node_to_index.at( n ); @@ -168,8 +176,6 @@ class window_view : public immutable_view { return is_pi( n ); } - - inline uint32_t fanout_size( node const& n ) const = delete; #pragma endregion #pragma region Node and signal iterators diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index aca29d1cd..a786108a6 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -31,7 +31,7 @@ bool window_is_well_formed( Ntk const& ntk ) bool all_fanins_belong_to_window = true; ntk.foreach_node( [&]( node const& n ){ ntk.foreach_fanin( n, [&]( signal const& fi ){ - if ( !ntk.belongs_to_window( ntk.get_node( fi ) ) ) + if ( !ntk.belongs_to( ntk.get_node( fi ) ) ) { all_fanins_belong_to_window = false; return false; /* terminate */ @@ -49,7 +49,7 @@ bool window_is_well_formed( Ntk const& ntk ) bool all_outputs_belong_to_window = true; ntk.foreach_po( [&]( signal const& o ){ - if ( !ntk.belongs_to_window( ntk.get_node( o ) ) ) + if ( !ntk.belongs_to( ntk.get_node( o ) ) ) { all_outputs_belong_to_window = false; return false; /* terminate */ @@ -90,10 +90,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) CHECK( view.num_cis() == 2 ); CHECK( view.num_cos() == 1 ); - CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f2 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + CHECK( view.belongs_to( view.get_node( f1 ) ) ); + CHECK( !view.belongs_to( view.get_node( f2 ) ) ); + CHECK( view.belongs_to( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to( view.get_node( f4 ) ) ); CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); CHECK( collect_fanin_nodes( view, view.get_node( f3 ) ).size() == 2 ); @@ -112,10 +112,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) CHECK( view.num_cis() == 2 ); CHECK( view.num_cos() == 1 ); - CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f2 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + CHECK( view.belongs_to( view.get_node( f1 ) ) ); + CHECK( !view.belongs_to( view.get_node( f2 ) ) ); + CHECK( view.belongs_to( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to( view.get_node( f4 ) ) ); CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 0 ); CHECK( collect_fanin_nodes( view, view.get_node( f3 ) ).size() == 2 ); @@ -135,10 +135,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) CHECK( view.num_cis() == 2 ); CHECK( view.num_cos() == 1 ); - CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f2 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f3 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + CHECK( view.belongs_to( view.get_node( f1 ) ) ); + CHECK( view.belongs_to( view.get_node( f2 ) ) ); + CHECK( !view.belongs_to( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to( view.get_node( f4 ) ) ); CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); CHECK( collect_fanin_nodes( view, view.get_node( f2 ) ).size() == 2 ); @@ -158,10 +158,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) CHECK( view.num_cis() == 2 ); CHECK( view.num_cos() == 1 ); - CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f2 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f4 ) ) ); + CHECK( view.belongs_to( view.get_node( f1 ) ) ); + CHECK( view.belongs_to( view.get_node( f2 ) ) ); + CHECK( view.belongs_to( view.get_node( f3 ) ) ); + CHECK( view.belongs_to( view.get_node( f4 ) ) ); CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); CHECK( collect_fanin_nodes( view, view.get_node( f2 ) ).size() == 2 ); @@ -183,10 +183,10 @@ TEST_CASE( "create new window view on AIG", "[window_view]" ) CHECK( view.num_cis() == 2 ); CHECK( view.num_cos() == 2 ); - CHECK( view.belongs_to_window( view.get_node( f1 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f2 ) ) ); - CHECK( view.belongs_to_window( view.get_node( f3 ) ) ); - CHECK( !view.belongs_to_window( view.get_node( f4 ) ) ); + CHECK( view.belongs_to( view.get_node( f1 ) ) ); + CHECK( view.belongs_to( view.get_node( f2 ) ) ); + CHECK( view.belongs_to( view.get_node( f3 ) ) ); + CHECK( !view.belongs_to( view.get_node( f4 ) ) ); CHECK( collect_fanin_nodes( view, view.get_node( f1 ) ).size() == 2 ); CHECK( collect_fanin_nodes( view, view.get_node( f2 ) ).size() == 2 ); From 0af84480dc6d493c74d76a4003ca8ffc1cfb344c Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 6 Oct 2020 09:55:42 +0200 Subject: [PATCH 06/30] window_view. --- include/mockturtle/views/window_view.hpp | 5 ++--- test/views/window_view.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/mockturtle/views/window_view.hpp b/include/mockturtle/views/window_view.hpp index b7274d49f..c938b133d 100644 --- a/include/mockturtle/views/window_view.hpp +++ b/include/mockturtle/views/window_view.hpp @@ -66,9 +66,8 @@ namespace mockturtle * support set. The outputs could be automatically computed. * * The window_view implements one new API method: - * 1.) `belongs_to`: takes a node as input and returns true if and - * only if this node is a constant, an input, or an inner node - * of the window + * 1.) `belongs_to`: takes a node (or a signal) and returns true if and + * only if the corresponding node belongs to the window */ template class window_view : public immutable_view diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index a786108a6..5f3cf3cf7 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -61,7 +61,7 @@ bool window_is_well_formed( Ntk const& ntk ) all_outputs_belong_to_window; } -TEST_CASE( "create new window view on AIG", "[window_view]" ) +TEST_CASE( "create window view on AIG", "[window_view]" ) { aig_network aig; const auto a = aig.create_pi(); From 3c229cc46585e397871ae1658f1e19a4cd3a53e2 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 6 Oct 2020 09:56:08 +0200 Subject: [PATCH 07/30] zero-cost TFI expansion. --- include/mockturtle/utils/window_utils.hpp | 72 +++++++++++++++++++++++ test/views/window_view.cpp | 66 +++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 7bda13397..2f5e957d4 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -356,4 +356,76 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& } } +/*! \brief Performs zero-cost expansion of a set of nodes towards TFI + * + * \param ntk A network + * \param inputs Input nodes + * \param colors Auxiliar data structure with `ntk.size()` elements + * \param color A value used to mark inputs + * \return True if and only if the inputs form a trivial cut that + * cannot be further extended, e.g., when the cut only + * consists of PIs. + * + * On termination, `colors[i] == color` if `i \in inputs`. However, + * previous inputs are also marked. + */ +template +bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs, std::vector& colors, uint32_t color ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + assert( ntk.size() == colors.size() ); + + /* mark all inputs */ + for ( auto const& i : inputs ) + { + colors[i] = color; + } + + /* we call a set of inputs (= a cut) trivial if all nodes are either + constants or CIs, such that they cannot be further expanded towards + the TFI */ + bool trivial_cut = false; + + /* repeat expansion towards TFI until a fix-point is reached */ + bool changed = true; + while ( changed ) + { + changed = false; + trivial_cut = true; + + for ( auto it = std::begin( inputs ); it != std::end( inputs ); ++it ) + { + /* count how many fanins are not in the cut */ + uint32_t count_fanin_outside{0}; + std::optional ep; + + ntk.foreach_fanin( *it, [&]( signal const& fi ){ + node const n = ntk.get_node( fi ); + trivial_cut = false; + + if ( colors[n] != color ) + { + ++count_fanin_outside; + ep = n; + } + }); + + /* if only one fanin is not in the cut, then the input expansion + can be done wihout affecting the cut size */ + if ( count_fanin_outside == 1u ) + { + /* expand the cut */ + assert( ep ); + it = inputs.erase( it ); + inputs.push_back( *ep ); + changed = true; + } + } + } + + return trivial_cut; +} + } /* namespace mockturtle */ diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 5f3cf3cf7..f217f5b50 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -251,3 +251,69 @@ TEST_CASE( "expand towards tfo", "[window_view]" ) CHECK( std::find( std::begin( gates ), std::end( gates ), n ) != std::end( gates ) ); }); } + +TEST_CASE( "zero-cost TFI expansion", "[window_utils]" ) +{ + using node = typename aig_network::node; + + aig_network aig; + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + auto const d = aig.create_pi(); + auto const f1 = aig.create_and( b, c ); + auto const f2 = aig.create_and( b, f1 ); + auto const f3 = aig.create_and( a, f2 ); + auto const f4 = aig.create_and( d, f2 ); + auto const f5 = aig.create_and( f3, f4 ); + aig.create_po( f5 ); + + write_dot( aig, std::cout ); + + std::vector colors( aig.size() ); + + { + /* a cut that can be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 1u ); + CHECK( trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + } + + { + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 2u ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); + } + + { + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 3u ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); + } + + { + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 4u ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); + } +} + From 407269c770363827a9f9ed84e813b3c00f8c3e1c Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 6 Oct 2020 09:58:19 +0200 Subject: [PATCH 08/30] remove printing. --- test/views/window_view.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index f217f5b50..690c11d45 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -268,8 +268,6 @@ TEST_CASE( "zero-cost TFI expansion", "[window_utils]" ) auto const f5 = aig.create_and( f3, f4 ); aig.create_po( f5 ); - write_dot( aig, std::cout ); - std::vector colors( aig.size() ); { From edce0ff6bc87038e67b9b81e39707d626352450d Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 6 Oct 2020 17:09:19 +0200 Subject: [PATCH 09/30] bugfix expand0_towards_tfi. --- include/mockturtle/utils/window_utils.hpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 2f5e957d4..d3f576432 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -390,12 +390,13 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input /* repeat expansion towards TFI until a fix-point is reached */ bool changed = true; + std::vector new_inputs; while ( changed ) { changed = false; trivial_cut = true; - for ( auto it = std::begin( inputs ); it != std::end( inputs ); ++it ) + for ( auto it = std::begin( inputs ); it != std::end( inputs ); ) { /* count how many fanins are not in the cut */ uint32_t count_fanin_outside{0}; @@ -419,10 +420,17 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input /* expand the cut */ assert( ep ); it = inputs.erase( it ); - inputs.push_back( *ep ); + new_inputs.push_back( *ep ); changed = true; } + else + { + ++it; + } } + + std::copy( std::begin( new_inputs ), std::end( new_inputs ), std::back_inserter( inputs ) ); + new_inputs.clear(); } return trivial_cut; From fac32332010f2b4d84112f3b22cf6fb08d44ddb9 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 6 Oct 2020 19:04:11 +0200 Subject: [PATCH 10/30] documentation: expand0_towards_tfi. --- include/mockturtle/utils/window_utils.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index d3f576432..b6001ee04 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -357,6 +357,11 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& } /*! \brief Performs zero-cost expansion of a set of nodes towards TFI + * + * The algorithm potentially derives a different cut of the same size + * that is closer to the network's PIs. This expansion towards TFI is + * called zero-cost because it merges nodes only if the number of + * inputs does not increase. * * \param ntk A network * \param inputs Input nodes @@ -368,9 +373,15 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * * On termination, `colors[i] == color` if `i \in inputs`. However, * previous inputs are also marked. + * + * **Required network functions:** + * - `size` + * - `foreach_fanin` + * - `get_node` */ template -bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs, std::vector& colors, uint32_t color ) +bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs, + std::vector& colors, uint32_t color ) { using node = typename Ntk::node; using signal = typename Ntk::signal; @@ -429,7 +440,8 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input } } - std::copy( std::begin( new_inputs ), std::end( new_inputs ), std::back_inserter( inputs ) ); + std::copy( std::begin( new_inputs ), std::end( new_inputs ), + std::back_inserter( inputs ) ); new_inputs.clear(); } From 82fe4487715fd8845098a91449313f5afd6d3914 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 6 Oct 2020 21:55:30 +0200 Subject: [PATCH 11/30] expand_towards_tfi. --- include/mockturtle/utils/window_utils.hpp | 96 +++++++++++++++++++++++ test/views/window_view.cpp | 58 +++++++++++++- 2 files changed, 153 insertions(+), 1 deletion(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index b6001ee04..d211b223a 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -235,6 +235,7 @@ inline std::vector find_outputs( Ntk const& ntk, return outputs; } + /*! \brief Expand a nodes towards TFO * * Iteratively expands the inner nodes of the window with those @@ -448,4 +449,99 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input return trivial_cut; } +namespace detail +{ + +template +inline void evaluate_fanin( typename Ntk::node const& n, std::vector>& candidates ) +{ + auto it = std::find_if( std::begin( candidates ), std::end( candidates ), + [&n]( auto const& p ){ + return p.first == n; + } ); + if ( it == std::end( candidates ) ) + { + candidates.push_back( std::make_pair( n, 1u ) ); + } + else + { + ++it->second; + } +} + +template +inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std::vector const& inputs ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + std::vector> candidates; + for ( auto const& i : inputs ) + { + if ( ntk.is_constant( i ) || ntk.is_ci( i ) ) + { + continue; + } + ntk.foreach_fanin( i, [&]( signal const& fi ){ + detail::evaluate_fanin( ntk.get_node( fi ), candidates ); + }); + } + + std::pair best_fanin; + for ( auto const& candidate : candidates ) + { + if ( candidate.second > best_fanin.second || + ( candidate.second == best_fanin.second && ntk.fanout_size( candidate.first ) > ntk.fanout_size( best_fanin.first ) ) ) + { + best_fanin = candidate; + } + } + + assert( best_fanin.first != 0 ); + return best_fanin.first; +} + +} /* namespace detail */ + +/*! \brief Performs expansion of a set of nodes towards TFI + * + * \param ntk A network + * \param inputs Input nodes + * \param input_limit Size limit for the maximum number of input nodes + * \param colors Auxiliar data structure with `ntk.size()` elements + * \param color A value used to mark inputs + */ +template +void expand_towards_tfi( Ntk const& ntk, std::vector& inputs, uint32_t input_limit, + std::vector& colors, uint32_t color ) +{ + using node = typename Ntk::node; + static constexpr uint32_t const MAX_ITERATIONS{5u}; + + if ( expand0_towards_tfi( ntk, inputs, colors, color ) ) + { + return; + } + + std::vector best_cut{inputs}; + bool trivial_cut = false; + uint32_t iterations{0}; + while ( !trivial_cut && ( inputs.size() <= input_limit || iterations <= MAX_ITERATIONS ) ) + { + node const n = detail::select_next_fanin_to_expand_tfi( ntk, inputs ); + inputs.push_back( n ); + colors[n] = color; + trivial_cut = expand0_towards_tfi( ntk, inputs, colors, color ); + + if ( inputs.size() <= input_limit ) + { + best_cut = inputs; + } + + iterations = inputs.size() > input_limit ? iterations + 1 : 0; + } + + inputs = best_cut; +} + } /* namespace mockturtle */ diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 690c11d45..d952a2215 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -252,7 +252,8 @@ TEST_CASE( "expand towards tfo", "[window_view]" ) }); } -TEST_CASE( "zero-cost TFI expansion", "[window_utils]" ) + +TEST_CASE( "expand node set towards TFI without increasing costs", "[window_utils]" ) { using node = typename aig_network::node; @@ -315,3 +316,58 @@ TEST_CASE( "zero-cost TFI expansion", "[window_utils]" ) } } +TEST_CASE( "expand node set towards TFI", "[window_utils]" ) +{ + using node = typename aig_network::node; + + aig_network aig; + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + auto const d = aig.create_pi(); + auto const f1 = aig.create_and( b, c ); + auto const f2 = aig.create_and( b, f1 ); + auto const f3 = aig.create_and( a, f2 ); + auto const f4 = aig.create_and( d, f2 ); + auto const f5 = aig.create_and( f3, f4 ); + aig.create_po( f5 ); + + std::vector colors( aig.size() ); + + { + /* a cut that can be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; + expand_towards_tfi( aig, inputs, 5u, colors, 1u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + } + + { + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; + expand_towards_tfi( aig, inputs, 4u, colors, 2u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + } + + { + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; + expand_towards_tfi( aig, inputs, 4u, colors, 3u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + } + + { + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 3u, colors, 4u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); + } +} + From 533758a207c066737bc3420910ef56afe09940b0 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 7 Oct 2020 10:36:09 +0200 Subject: [PATCH 12/30] cleanup test cases. --- test/views/window_view.cpp | 47 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index d952a2215..e6009a247 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -253,7 +253,7 @@ TEST_CASE( "expand towards tfo", "[window_view]" ) } -TEST_CASE( "expand node set towards TFI without increasing costs", "[window_utils]" ) +TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) { using node = typename aig_network::node; @@ -294,7 +294,7 @@ TEST_CASE( "expand node set towards TFI without increasing costs", "[window_util } { - /* a cut that cannot be expanded without increasing cut-size */ + /* a cut that can be moved towards the PIs */ std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 3u ); @@ -305,7 +305,7 @@ TEST_CASE( "expand node set towards TFI without increasing costs", "[window_util } { - /* a cut that cannot be expanded without increasing cut-size */ + /* the cut { f3, f5 } can be simplified to { f3, f4 } */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 4u ); @@ -314,6 +314,17 @@ TEST_CASE( "expand node set towards TFI without increasing costs", "[window_util std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); } + + { + /* the cut { f4, f5 } also can be simplified to { f3, f4 } */ + std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 5u ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); + } } TEST_CASE( "expand node set towards TFI", "[window_utils]" ) @@ -335,39 +346,37 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) std::vector colors( aig.size() ); { - /* a cut that can be expanded without increasing cut-size */ - std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; - expand_towards_tfi( aig, inputs, 5u, colors, 1u ); + /* expand from { f5 } to 4-cut { a, b, c, d } */ + std::vector inputs{aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 4u, colors, 1u ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); } { - /* a cut that cannot be expanded without increasing cut-size */ - std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; - expand_towards_tfi( aig, inputs, 4u, colors, 2u ); + /* expand from { f3, f5 } to 3-cut { a, b, f2 } */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 3u, colors, 2u ); std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); } { - /* a cut that cannot be expanded without increasing cut-size */ - std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; - expand_towards_tfi( aig, inputs, 4u, colors, 3u ); + /* expand from { f4, f5 } to 3-cut { a, b, f2 } */ + std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 3u, colors, 3u ); std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); + } +} + } { - /* a cut that cannot be expanded without increasing cut-size */ - std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u, colors, 4u ); - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); } } From 560530e54a748f133c3c730af6853a5a0756fddc Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 7 Oct 2020 10:50:08 +0200 Subject: [PATCH 13/30] better documentation for TFI expansion. --- include/mockturtle/utils/window_utils.hpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index d211b223a..409df0242 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -357,7 +357,7 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& } } -/*! \brief Performs zero-cost expansion of a set of nodes towards TFI +/*! \brief Performs in-place zero-cost expansion of a set of nodes towards TFI * * The algorithm potentially derives a different cut of the same size * that is closer to the network's PIs. This expansion towards TFI is @@ -461,10 +461,12 @@ inline void evaluate_fanin( typename Ntk::node const& n, std::vectorsecond; } } @@ -475,6 +477,10 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: using node = typename Ntk::node; using signal = typename Ntk::signal; + assert( inputs.size() > 0u && "inputs must not be empty" ); + // assert( cut_is_not_trivial( inputs ) ); + + /* evaluate the fanins with respect to their costs (how often are they referenced) */ std::vector> candidates; for ( auto const& i : inputs ) { @@ -487,6 +493,7 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: }); } + /* select the fanin with maximum reference count; if two fanins have equal reference count, select the one with more fanouts */ std::pair best_fanin; for ( auto const& candidate : candidates ) { @@ -497,13 +504,22 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: } } + /* as long as the inputs do not form a trivial cut, this procedure will always find a fanin to expand */ assert( best_fanin.first != 0 ); + return best_fanin.first; } } /* namespace detail */ -/*! \brief Performs expansion of a set of nodes towards TFI +/*! \brief Performs in-place expansion of a set of nodes towards TFI + * + * Expand the inputs towards TFI by iteratively selecting the fanins + * with the highest reference count within the cut and highest number + * of fanouts. Expansion continues until either `inputs` forms a + * trivial cut or the `inputs`'s size reaches `input_limit`. The + * procedure allows a temporary increase of `inputs` beyond the + * `input_limit` for at most `MAX_ITERATIONS`. * * \param ntk A network * \param inputs Input nodes From 655ee1420a7136e44f97814ca523c24f0b887352 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 7 Oct 2020 11:32:21 +0200 Subject: [PATCH 14/30] `levelized_expand_towards_tfo`, --- include/mockturtle/utils/window_utils.hpp | 347 ++++++++++++++-------- test/views/window_view.cpp | 8 - 2 files changed, 225 insertions(+), 130 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 409df0242..459dcf1aa 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -235,128 +235,6 @@ inline std::vector find_outputs( Ntk const& ntk, return outputs; } - -/*! \brief Expand a nodes towards TFO - * - * Iteratively expands the inner nodes of the window with those - * fanouts that are supported by the window until a fixed-point is - * reached. - * - * \param ntk A network - * \param inputs Input nodes of a window - * \param nodes Inner nodes of a window - * - * **Required network functions:** - * - `foreach_fanin` - * - `foreach_fanout` - * - `get_node` - * - `incr_trav_id` - * - `is_ci` - * - `set_visited` - * - `trav_id` - * - `visited` - */ -template -void expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) -{ - using node = typename Ntk::node; - using signal = typename Ntk::signal; - - auto explore_fanouts = [&]( Ntk const& ntk, node const& n, std::set& result ){ - ntk.foreach_fanout( n, [&]( node const& fo, uint64_t index ){ - /* only look at the first few fanouts */ - if ( index > 5 ) - { - return false; - } - /* skip all nodes that are already in nodex */ - if ( ntk.visited( fo ) == ntk.trav_id() ) - { - return true; - } - result.insert( fo ); - return true; - }); - }; - - /* create a new traversal ID */ - ntk.incr_trav_id(); - - /* mark the inputs visited */ - for ( auto const& i : inputs ) - { - ntk.set_visited( i, ntk.trav_id() ); - } - /* mark the nodes visited */ - for ( const auto& n : nodes ) - { - ntk.set_visited( n, ntk.trav_id() ); - } - - /* collect all nodes that have fanouts not yet contained in nodes */ - std::set eps; - for ( const auto& n : inputs ) - { - explore_fanouts( ntk, n, eps ); - } - for ( const auto& n : nodes ) - { - explore_fanouts( ntk, n, eps ); - } - - bool changed = true; - std::set new_eps; - while ( changed ) - { - new_eps.clear(); - changed = false; - - auto it = std::begin( eps ); - while ( it != std::end( eps ) ) - { - node const ep = *it; - if ( ntk.visited( ep ) == ntk.trav_id() ) - { - it = eps.erase( it ); - continue; - } - - bool all_children_belong_to_window = true; - ntk.foreach_fanin( ep, [&]( signal const& fi ){ - node const child = ntk.get_node( fi ); - if ( ntk.visited( child ) != ntk.trav_id() ) - { - all_children_belong_to_window = false; - return false; - } - return true; - }); - - if ( all_children_belong_to_window ) - { - assert( ep != 0 ); - assert( !ntk.is_ci( ep ) ); - nodes.emplace_back( ep ); - ntk.set_visited( ep, ntk.trav_id() ); - it = eps.erase( it ); - - explore_fanouts( ntk, ep, new_eps ); - } - - if ( it != std::end( eps ) ) - { - ++it; - } - } - - if ( !new_eps.empty() ) - { - eps.insert( std::begin( new_eps ), std::end( new_eps ) ); - changed = true; - } - } -} - /*! \brief Performs in-place zero-cost expansion of a set of nodes towards TFI * * The algorithm potentially derives a different cut of the same size @@ -532,6 +410,7 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs std::vector& colors, uint32_t color ) { using node = typename Ntk::node; + static constexpr uint32_t const MAX_ITERATIONS{5u}; if ( expand0_towards_tfi( ntk, inputs, colors, color ) ) @@ -560,4 +439,228 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs inputs = best_cut; } +/*! \brief Performs in-place expansion of a set of nodes towards TFO + * + * Iteratively expands the inner nodes of the window with those + * fanouts that are supported by the window until a fixed-point is + * reached. + * + * \param ntk A network + * \param inputs Input nodes of a window + * \param nodes Inner nodes of a window + * + * **Required network functions:** + * - `foreach_fanin` + * - `foreach_fanout` + * - `get_node` + * - `incr_trav_id` + * - `is_ci` + * - `set_visited` + * - `trav_id` + * - `visited` + */ +template +void expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + auto explore_fanouts = [&]( Ntk const& ntk, node const& n, std::set& result ){ + ntk.foreach_fanout( n, [&]( node const& fo, uint64_t index ){ + /* only look at the first few fanouts */ + if ( index > 5 ) + { + return false; + } + /* skip all nodes that are already in nodex */ + if ( ntk.visited( fo ) == ntk.trav_id() ) + { + return true; + } + result.insert( fo ); + return true; + }); + }; + + /* create a new traversal ID */ + ntk.incr_trav_id(); + + /* mark the inputs visited */ + for ( auto const& i : inputs ) + { + ntk.set_visited( i, ntk.trav_id() ); + } + /* mark the nodes visited */ + for ( const auto& n : nodes ) + { + ntk.set_visited( n, ntk.trav_id() ); + } + + /* collect all nodes that have fanouts not yet contained in nodes */ + std::set eps; + for ( const auto& n : inputs ) + { + explore_fanouts( ntk, n, eps ); + } + for ( const auto& n : nodes ) + { + explore_fanouts( ntk, n, eps ); + } + + bool changed = true; + std::set new_eps; + while ( changed ) + { + new_eps.clear(); + changed = false; + + auto it = std::begin( eps ); + while ( it != std::end( eps ) ) + { + node const ep = *it; + if ( ntk.visited( ep ) == ntk.trav_id() ) + { + it = eps.erase( it ); + continue; + } + + bool all_children_belong_to_window = true; + ntk.foreach_fanin( ep, [&]( signal const& fi ){ + node const child = ntk.get_node( fi ); + if ( ntk.visited( child ) != ntk.trav_id() ) + { + all_children_belong_to_window = false; + return false; + } + return true; + }); + + if ( all_children_belong_to_window ) + { + assert( ep != 0 ); + assert( !ntk.is_ci( ep ) ); + nodes.emplace_back( ep ); + ntk.set_visited( ep, ntk.trav_id() ); + it = eps.erase( it ); + + explore_fanouts( ntk, ep, new_eps ); + } + + if ( it != std::end( eps ) ) + { + ++it; + } + } + + if ( !new_eps.empty() ) + { + eps.insert( std::begin( new_eps ), std::end( new_eps ) ); + changed = true; + } + } +} + +/*! \brief Performs in-place expansion of a set of nodes towards TFO + * + * Iteratively expands the inner nodes of the window with those + * fanouts that are supported by the window. Explores the fanouts + * level by level. Starting with those that are closest to the + * inputs. + * + * \param ntk A network + * \param inputs Input nodes of a window + * \param nodes Inner nodes of a window + * \param colors Auxiliar data structure with `ntk.size()` elements + * \param color A value used to mark inputs + */ +template +void levelized_expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes, + std::vector& colors, uint32_t color ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + static constexpr uint32_t const MAX_FANOUTS{5u}; + + /* returns true if and only if `n` is marked with `color` */ + auto is_colored = [&]( node const& n ) -> bool + { + return colors.at( n ) == color; + }; + + /* returns true if and only if all fanins of `n` are marked with `color` */ + auto all_fanins_colored = [&]( node const& n ) -> bool + { + bool result = true; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + if ( !is_colored( ntk.get_node( fi ) ) ) + { + result = false; + return false; + } + return true; + }); + return result; + }; + + /* mapping from level to nodes (which nodes are on a certain level?) */ + std::vector> levels; + + /* list of indicves of used levels (avoid iterating over all levels) */ + std::vector used; + + /* remove all nodes */ + nodes.clear(); + + /* mark all inputs and add fill their level information into `levels` and `used` */ + for ( const auto& i : inputs ) + { + uint32_t const node_level = ntk.level( i ); + colors[i] = color; + levels[node_level].push_back( i ); + if ( std::find( std::begin( used ), std::end( used ), node_level ) == std::end( used ) ) + { + used.push_back( node_level ); + } + } + + for ( uint32_t const& index : used ) + { + std::vector& level = levels.at( index ); + for ( auto it = std::begin( level ); it != std::end( level ); ++it ) + { + node const n = *it; + ntk.foreach_fanout( n, [&]( node const& fo, uint64_t index ){ + /* avoid getting stuck on nodes with many fanouts */ + if ( index == MAX_FANOUTS ) + { + return false; + } + + /* ignore nodes wihout fanins */ + if ( ntk.is_constant( fo ) || ntk.is_ci( fo ) ) + { + return true; + } + + if ( !is_colored( fo ) && all_fanins_colored( fo ) ) + { + /* add fanout to nodes */ + nodes.push_back( fo ); + + /* update data structured */ + uint32_t const node_level = ntk.level( fo ); + colors[fo] = color; + levels.at( node_level ).push_back( fo ); + if ( std::find( std::begin( used ), std::end( used ), node_level ) == std::end( used ) ) + { + used.push_back( node_level ); + } + } + }); + } + level.clear(); + } +} + } /* namespace mockturtle */ diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index e6009a247..8f4dd985b 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -372,11 +372,3 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); } } - - } - - { - - } -} - From 853eea3a0160c8e9d5a8d7d4a4de1521a41ba157 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 7 Oct 2020 13:16:40 +0200 Subject: [PATCH 15/30] refactory: use abstract colors_map. --- include/mockturtle/utils/window_utils.hpp | 76 ++++----- test/views/window_view.cpp | 179 ++++++++++++++++++++-- 2 files changed, 198 insertions(+), 57 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 459dcf1aa..4383fa7c9 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -244,8 +244,7 @@ inline std::vector find_outputs( Ntk const& ntk, * * \param ntk A network * \param inputs Input nodes - * \param colors Auxiliar data structure with `ntk.size()` elements - * \param color A value used to mark inputs + * \param colors Auxiliar data structure to mark nodes * \return True if and only if the inputs form a trivial cut that * cannot be further extended, e.g., when the cut only * consists of PIs. @@ -258,19 +257,17 @@ inline std::vector find_outputs( Ntk const& ntk, * - `foreach_fanin` * - `get_node` */ -template +template bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs, - std::vector& colors, uint32_t color ) + ColorMap& colors ) { using node = typename Ntk::node; using signal = typename Ntk::signal; - assert( ntk.size() == colors.size() ); - /* mark all inputs */ for ( auto const& i : inputs ) { - colors[i] = color; + colors.paint( i ); } /* we call a set of inputs (= a cut) trivial if all nodes are either @@ -296,7 +293,7 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input node const n = ntk.get_node( fi ); trivial_cut = false; - if ( colors[n] != color ) + if ( !colors.colored( n ) ) { ++count_fanin_outside; ep = n; @@ -402,18 +399,17 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: * \param ntk A network * \param inputs Input nodes * \param input_limit Size limit for the maximum number of input nodes - * \param colors Auxiliar data structure with `ntk.size()` elements - * \param color A value used to mark inputs + * \param colors Auxiliar data structure to mark nodes */ -template +template void expand_towards_tfi( Ntk const& ntk, std::vector& inputs, uint32_t input_limit, - std::vector& colors, uint32_t color ) + ColorMap& colors ) { using node = typename Ntk::node; static constexpr uint32_t const MAX_ITERATIONS{5u}; - if ( expand0_towards_tfi( ntk, inputs, colors, color ) ) + if ( expand0_towards_tfi( ntk, inputs, colors ) ) { return; } @@ -425,8 +421,8 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs { node const n = detail::select_next_fanin_to_expand_tfi( ntk, inputs ); inputs.push_back( n ); - colors[n] = color; - trivial_cut = expand0_towards_tfi( ntk, inputs, colors, color ); + colors.paint( n ); + trivial_cut = expand0_towards_tfi( ntk, inputs, colors ); if ( inputs.size() <= input_limit ) { @@ -570,41 +566,26 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * \param ntk A network * \param inputs Input nodes of a window * \param nodes Inner nodes of a window - * \param colors Auxiliar data structure with `ntk.size()` elements - * \param color A value used to mark inputs + * \param colors Auxiliar data structure to mark nodes + * + * **Required network functions:** + * - `foreach_fanin` + * - `foreach_fanout` + * - `get_node` + * - `level` + * - `is_constant` + * - `is_ci` */ -template +template void levelized_expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes, - std::vector& colors, uint32_t color ) + ColorMap& colors ) { using node = typename Ntk::node; - using signal = typename Ntk::signal; static constexpr uint32_t const MAX_FANOUTS{5u}; - /* returns true if and only if `n` is marked with `color` */ - auto is_colored = [&]( node const& n ) -> bool - { - return colors.at( n ) == color; - }; - - /* returns true if and only if all fanins of `n` are marked with `color` */ - auto all_fanins_colored = [&]( node const& n ) -> bool - { - bool result = true; - ntk.foreach_fanin( n, [&]( signal const& fi ){ - if ( !is_colored( ntk.get_node( fi ) ) ) - { - result = false; - return false; - } - return true; - }); - return result; - }; - /* mapping from level to nodes (which nodes are on a certain level?) */ - std::vector> levels; + std::vector> levels( ntk.depth() ); /* list of indicves of used levels (avoid iterating over all levels) */ std::vector used; @@ -616,7 +597,7 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector& level = levels.at( index ); for ( auto it = std::begin( level ); it != std::end( level ); ++it ) { - node const n = *it; - ntk.foreach_fanout( n, [&]( node const& fo, uint64_t index ){ + ntk.foreach_fanout( *it, [&]( node const& fo, uint64_t index ){ /* avoid getting stuck on nodes with many fanouts */ if ( index == MAX_FANOUTS ) { @@ -643,20 +623,22 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector #include #include +#include #include using namespace mockturtle; +template +struct colors_impl1 +{ +public: + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +public: + colors_impl1( Ntk const& ntk ) + : ntk( ntk ) + { + ntk.incr_trav_id(); + } + + void new_color() + { + ntk.incr_trav_id(); + } + + uint32_t color() const + { + return ntk.trav_id(); + } + + bool colored( node const& n ) const + { + return ntk.visited( n ) == ntk.trav_id(); + } + + bool fanins_colored( node const& n ) const + { + bool result = true; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + if ( !colored( ntk.get_node( fi ) ) ) + { + result = false; + return false; + } + return true; + }); + return result; + } + + void paint( node const& n ) + { + ntk.set_visited( n, ntk.trav_id() ); + } + +protected: + Ntk const& ntk; +}; + +template +struct colors_impl2 +{ +public: + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +public: + colors_impl2( Ntk const& ntk ) + : ntk( ntk ) + , values( ntk.size() ) + {} + + void new_color() + { + ++value; + } + + uint32_t color() const + { + return value; + } + + bool colored( node const& n ) const + { + return values[n] == value; + } + + bool fanins_colored( node const& n ) const + { + bool result = true; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + if ( !colored( ntk.get_node( fi ) ) ) + { + result = false; + return false; + } + return true; + }); + return result; + } + + void paint( node const& n ) + { + values[n] = value; + } + +protected: + Ntk const& ntk; + std::vector values; + uint32_t value{1}; +}; + template std::vector collect_fanin_nodes( Ntk const& ntk, typename Ntk::node const& n ) { @@ -269,13 +375,13 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) auto const f5 = aig.create_and( f3, f4 ); aig.create_po( f5 ); - std::vector colors( aig.size() ); + colors_impl1 colors( aig ); { /* a cut that can be expanded without increasing cut-size */ std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 1u ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); CHECK( trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -283,10 +389,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { + colors.new_color(); + /* a cut that cannot be expanded without increasing cut-size */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 2u ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -294,10 +402,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { + colors.new_color(); + /* a cut that can be moved towards the PIs */ std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 3u ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -305,10 +415,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { + colors.new_color(); + /* the cut { f3, f5 } can be simplified to { f3, f4 } */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 4u ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -316,10 +428,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { + colors.new_color(); + /* the cut { f4, f5 } also can be simplified to { f3, f4 } */ std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors, 5u ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -343,32 +457,77 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) auto const f5 = aig.create_and( f3, f4 ); aig.create_po( f5 ); - std::vector colors( aig.size() ); + colors_impl1 colors( aig ); { /* expand from { f5 } to 4-cut { a, b, c, d } */ std::vector inputs{aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 4u, colors, 1u ); + expand_towards_tfi( aig, inputs, 4u, colors ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); } { + colors.new_color(); + /* expand from { f3, f5 } to 3-cut { a, b, f2 } */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u, colors, 2u ); + expand_towards_tfi( aig, inputs, 3u, colors ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); } { + colors.new_color(); + /* expand from { f4, f5 } to 3-cut { a, b, f2 } */ std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u, colors, 3u ); + expand_towards_tfi( aig, inputs, 3u, colors ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); } } + +TEST_CASE( "expand node set towards TFO", "[window_utils]" ) +{ + using node = typename aig_network::node; + + aig_network aig; + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + auto const d = aig.create_pi(); + auto const f1 = aig.create_and( b, c ); + auto const f2 = aig.create_and( b, f1 ); + auto const f3 = aig.create_and( a, f2 ); + auto const f4 = aig.create_and( d, f2 ); + auto const f5 = aig.create_and( f3, f4 ); + aig.create_po( f5 ); + + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; + + fanout_view fanout_aig{aig}; + depth_view depth_aig{fanout_aig}; + + { + std::vector nodes; + expand_towards_tfo( depth_aig, inputs, nodes ); + + std::sort( std::begin( nodes ), std::end( nodes ) ); + CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), + aig.get_node( f4 ), aig.get_node( f5 )} ); + } + + colors_impl1 colors( aig ); + + { + std::vector nodes; + levelized_expand_towards_tfo( depth_aig, inputs, nodes, colors ); + + std::sort( std::begin( nodes ), std::end( nodes ) ); + CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f4 )} ); + } +} From 832851f0353036b21132d67ece15b47068c8891f Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 7 Oct 2020 15:55:39 +0200 Subject: [PATCH 16/30] create_window. --- test/views/window_view.cpp | 160 +++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 7843cf5e1..3d2979b80 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -38,6 +38,16 @@ struct colors_impl1 return ntk.visited( n ) == ntk.trav_id(); } + bool colored( node const& n, uint32_t k ) const + { + return ntk.visited( n ) >= ntk.trav_id() - k; + } + + bool same_color( node const& a, node const& b ) const + { + return ntk.visited( a ) == ntk.visited( b ); + } + bool fanins_colored( node const& n ) const { bool result = true; @@ -57,6 +67,11 @@ struct colors_impl1 ntk.set_visited( n, ntk.trav_id() ); } + void paint( node const& n, node const& a ) + { + ntk.set_visited( n, ntk.visited( a ) ); + } + protected: Ntk const& ntk; }; @@ -89,6 +104,16 @@ struct colors_impl2 return values[n] == value; } + bool colored( node const& n, uint32_t k ) const + { + return values[n] >= value - k; + } + + bool same_color( node const& a, node const& b ) const + { + return values[a] == values[b]; + } + bool fanins_colored( node const& n ) const { bool result = true; @@ -108,6 +133,12 @@ struct colors_impl2 values[n] = value; } + void paint( node const& n, node const& a ) + { + values[n] = values[a]; + ntk.set_visited( n, ntk.visited( a ) ); + } + protected: Ntk const& ntk; std::vector values; @@ -359,6 +390,135 @@ TEST_CASE( "expand towards tfo", "[window_view]" ) } +template +class create_window_impl2 +{ +public: + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +protected: + /* constant node used to denotes invalid window element */ + static constexpr node INVALID_NODE{0}; + +public: + create_window_impl2( Ntk const& ntk ) + : ntk( ntk ) + , colors( ntk ) + , path( ntk.size() ) + { + } + + void run( node const& pivot ) + { + std::vector inputs; + std::optional> nodes; + std::vector outputs; + + /* find a reconvergence from the pivot and collect the nodes */ + if ( !( nodes = identify_reconvergence( pivot, 1u ) ) ) + { + /* if there is no reconvergence, then optimization is not possible */ + return; + } + } + +protected: + std::optional> identify_reconvergence( node const& pivot, uint64_t num_iterations ) + { + std::vector visited; + + ntk.foreach_fanin( pivot, [&]( signal const& fi ){ + colors.new_color(); + + node const& n = ntk.get_node( fi ); + colors.paint( n ); + path[n] = INVALID_NODE; + visited.push_back( n ); + }); + + uint64_t start{0}; + uint64_t stop; + for ( uint32_t iteration = 0u; iteration < num_iterations; ++iteration ) + { + stop = visited.size(); + for ( uint32_t i = start; i < stop; ++i ) + { + node const n = visited.at( i ); + std::optional meet = explore_frontier_of_node( n ); + if ( meet ) + { + visited.clear(); + gather_nodes_recursively( *meet ); + gather_nodes_recursively( n ); + visited.push_back( pivot ); + return visited; + } + } + start = stop; + } + + return std::nullopt; + } + + std::optional explore_frontier_of_node( node const& n ) + { + std::optional meet; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + node const& fi_node = ntk.get_node( fi ); + if ( ntk.is_constant( fi_node ) || ntk.is_ci( fi_node ) ) + { + return true; /* next */ + } + + if ( colors.colored( n, ntk.max_fanin_size - 1 ) && + colors.colored( fi_node, ntk.max_fanin_size - 1 ) && + !colors.same_color( n, fi_node ) ) + { + meet = fi_node; + return false; + } + + if ( is_path_colored( fi_node ) ) + { + return true; /* next */ + } + + colors.paint( fi_node, n ); + path[fi_node] = n; + visited.push_back( fi_node ); + return true; /* next */ + }); + + return meet; + } + + /* collect nodes recursively following along the `path` until INVALID_NODE is reached */ + void gather_nodes_recursively( node const& n ) + { + if ( n == INVALID_NODE ) + { + return; + } + + visited.push_back( n ); + node const pred = path[n]; + if ( pred == INVALID_NODE ) + { + return; + } + + assert( have_same_color( n, pred ) ); + gather_nodes_recursively( pred ); + } + +protected: + Ntk const& ntk; + colors_impl1 colors; + std::vector visited; + std::vector path; +}; /* create_window_impl */ + TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) { using node = typename aig_network::node; From 522bf7bed0c95ed15982403386e5bb1de3f8a84d Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 7 Oct 2020 19:17:59 +0200 Subject: [PATCH 17/30] create_window. --- include/mockturtle/utils/window_utils.hpp | 57 +++++++++++++---- test/views/window_view.cpp | 77 ++++++++++++++++++++--- 2 files changed, 112 insertions(+), 22 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 4383fa7c9..c3b36fc18 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -142,6 +142,39 @@ inline std::vector collect_nodes( Ntk const& ntk, return nodes; } +/*! \brief Identify inputs using reference counting + */ +template +std::vector collect_inputs( Ntk const& ntk, std::vector const& nodes, ColorMap& colors ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + /* mark all nodes with a new color */ + for ( const auto& n : nodes ) + { + colors.paint( n ); + } + + /* if a fanin is not colored, then it's an input */ + std::vector inputs; + for ( const auto& n : nodes ) + { + ntk.foreach_fanin( n, [&]( signal const& fi ){ + node const n = ntk.get_node( fi ); + if ( !colors.colored( n ) ) + { + if ( std::find( std::begin( inputs ), std::end( inputs ), n ) == std::end( inputs ) ) + { + inputs.push_back( n ); + } + } + }); + } + + return inputs; +} + /*! \brief Identify outputs using reference counting * * Identify outputs using a reference counting approach. The @@ -157,6 +190,7 @@ inline std::vector collect_nodes( Ntk const& ntk, * inputs and nodes is assumed to be empty) * \param refs Reference counters (in the size of the network and * initialized to 0) + * \param colors * \return Output signals of the window * * **Required network functions:** @@ -171,28 +205,27 @@ inline std::vector collect_nodes( Ntk const& ntk, * - `trav_id` * - `visited` */ -template -inline std::vector find_outputs( Ntk const& ntk, - std::vector const& inputs, - std::vector const& nodes, - std::vector& refs ) + template +inline std::vector collect_outputs( Ntk const& ntk, + std::vector const& inputs, + std::vector const& nodes, + std::vector& refs, + ColorMap& colors ) { using signal = typename Ntk::signal; - std::vector outputs; - /* create a new traversal ID */ - ntk.incr_trav_id(); + std::vector outputs; /* mark the inputs visited */ for ( auto const& i : inputs ) { - ntk.set_visited( i, ntk.trav_id() ); + colors.paint( i ); } /* reference fanins of nodes */ for ( auto const& n : nodes ) { - if ( ntk.visited( n ) == ntk.trav_id() ) + if ( colors.colored( n ) ) { continue; } @@ -207,7 +240,7 @@ inline std::vector find_outputs( Ntk const& ntk, the node has fanout outside of the window is an output */ for ( const auto& n : nodes ) { - if ( ntk.visited( n ) == ntk.trav_id() ) + if ( colors.colored( n ) ) { continue; } @@ -221,7 +254,7 @@ inline std::vector find_outputs( Ntk const& ntk, /* dereference fanins of nodes */ for ( auto const& n : nodes ) { - if ( ntk.visited( n ) == ntk.trav_id() ) + if ( colors.colored( n ) ) { continue; } diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 3d2979b80..2751be5e6 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -397,6 +397,13 @@ class create_window_impl2 using node = typename Ntk::node; using signal = typename Ntk::signal; + struct window_info + { + std::vector inputs; + std::vector nodes; + std::vector outputs; + }; + protected: /* constant node used to denotes invalid window element */ static constexpr node INVALID_NODE{0}; @@ -406,28 +413,49 @@ class create_window_impl2 : ntk( ntk ) , colors( ntk ) , path( ntk.size() ) + , refs( ntk.size() ) { } - void run( node const& pivot ) + std::optional run( node const& pivot ) { - std::vector inputs; - std::optional> nodes; - std::vector outputs; - /* find a reconvergence from the pivot and collect the nodes */ + std::optional> nodes; if ( !( nodes = identify_reconvergence( pivot, 1u ) ) ) { /* if there is no reconvergence, then optimization is not possible */ - return; + return std::nullopt; } + + /* collect the fanins for these nodes */ + colors.new_color(); + std::vector inputs = collect_inputs( ntk, *nodes, colors ); + + /* expand the nodes towards the TFI */ + colors.new_color(); + expand_towards_tfi( ntk, inputs, 6u, colors ); + + /* expand the nodes towards the TFO */ + colors.new_color(); + expand_towards_tfi( ntk, inputs, 6u, colors ); + levelized_expand_towards_tfo( ntk, inputs, *nodes, colors ); + + /* collect the nodes with fanout outside of nodes */ + colors.new_color(); + std::vector outputs = collect_outputs( ntk, inputs, *nodes, refs, colors ); + + /* sort nodes */ + std::sort( std::begin( inputs ), std::end( inputs ) ); + std::sort( std::begin( *nodes ), std::end( *nodes ) ); + + return window_info{inputs, *nodes, outputs}; } protected: std::optional> identify_reconvergence( node const& pivot, uint64_t num_iterations ) { - std::vector visited; - + visited.clear(); + ntk.foreach_fanin( pivot, [&]( signal const& fi ){ colors.new_color(); @@ -479,7 +507,7 @@ class create_window_impl2 return false; } - if ( is_path_colored( fi_node ) ) + if ( colors.colored( fi_node, ntk.max_fanin_size - 1 ) ) { return true; /* next */ } @@ -508,7 +536,7 @@ class create_window_impl2 return; } - assert( have_same_color( n, pred ) ); + assert( colors.same_color( n, pred ) ); gather_nodes_recursively( pred ); } @@ -517,6 +545,7 @@ class create_window_impl2 colors_impl1 colors; std::vector visited; std::vector path; + std::vector refs; }; /* create_window_impl */ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) @@ -691,3 +720,31 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f4 )} ); } } + +TEST_CASE( "make a window", "[create_window]" ) +{ + aig_network aig; + auto const a = aig.create_pi(); + auto const b = aig.create_pi(); + auto const c = aig.create_pi(); + auto const d = aig.create_pi(); + auto const f1 = aig.create_and( b, c ); + auto const f2 = aig.create_and( b, f1 ); + auto const f3 = aig.create_and( a, f2 ); + auto const f4 = aig.create_and( d, f2 ); + auto const f5 = aig.create_and( f3, f4 ); + aig.create_po( f5 ); + + fanout_view fanout_aig{aig}; + depth_view depth_aig{fanout_aig}; + + create_window_impl2 windowing( depth_aig ); + auto info = windowing.run( depth_aig.get_node( f5 ) ); + if ( info ) + { + window_view win( aig, info->inputs, info->outputs, info->nodes ); + CHECK( win.num_cis() == 4u ); + CHECK( win.num_cos() == 2u ); + CHECK( win.num_gates() == 4u ); + } +} From 7883bc6be28826d58d95fd2e0bcaffa009ebcd33 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 8 Oct 2020 18:45:54 +0200 Subject: [PATCH 18/30] missing header. --- lib/abcesop/exor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/abcesop/exor.cpp b/lib/abcesop/exor.cpp index e63b11647..041788840 100644 --- a/lib/abcesop/exor.cpp +++ b/lib/abcesop/exor.cpp @@ -48,6 +48,7 @@ #include "eabc/exor.h" #include +#include namespace abc::exorcism { From f47b454b8c1d57e9efb2ee925a4ac9984f099300 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 13:17:21 +0200 Subject: [PATCH 19/30] color_view. --- include/mockturtle/views/color_view.hpp | 229 ++++++++++++++++++++++++ test/views/color_view.cpp | 139 ++++++++++++++ 2 files changed, 368 insertions(+) create mode 100644 include/mockturtle/views/color_view.hpp create mode 100644 test/views/color_view.cpp diff --git a/include/mockturtle/views/color_view.hpp b/include/mockturtle/views/color_view.hpp new file mode 100644 index 000000000..e5f036cd7 --- /dev/null +++ b/include/mockturtle/views/color_view.hpp @@ -0,0 +1,229 @@ +/* mockturtle: C++ logic network library + * Copyright (C) 2018-2020 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 color_view.hpp + \brief Color view + + \author Heinz Riener +*/ + +#pragma once + +namespace mockturtle +{ + +/*!\brief Manager view for traversal IDs (in-place storage). + * + * Traversal IDs, called colors, are unsigned integers that can be + * assigned to nodes. The corresponding values are stored in-place in + * the flags of the underlying of the network. + */ +template +class color_view : public Ntk +{ +public: + using storage = typename Ntk::storage; + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +public: + explicit color_view( Ntk const& ntk ) + : Ntk( ntk ) + { + static_assert( is_network_type_v, "Ntk is not a network type" ); + } + + /*! \brief Returns a new color and increases the current color */ + uint32_t new_color() + { + return ++value; + } + + /*! \brief Returns the current color */ + uint32_t current_color() const + { + return value; + } + + /*! \brief Assigns all nodes to `color` */ + void clear( uint32_t color = 0 ) const + { + std::for_each( this->_storage->nodes.begin(), this->_storage->nodes.end(), + [color]( auto& n ) { n.data[1].h1 = color; } ); + } + + /*! \brief Returns the color of a node */ + auto color( node const& n ) const + { + return this->_storage->nodes[n].data[1].h1; + } + + /*! \brief Assigns the current color to a node */ + void paint( node const& n ) const + { + this->_storage->nodes[n].data[1].h1 = value; + } + + /*! \brief Assigns `color` to a node */ + void paint( node const& n, uint32_t color ) const + { + this->_storage->nodes[n].data[1].h1 = color; + } + + /*! \brief Copies the color from `other` to `n` */ + void paint( node const& n, node const& other ) const + { + this->_storage->nodes[n].data[1].h1 = color( other ); + } + + /*! \brief Evaluates a predicate on the color of a node */ + template + bool eval_color( node const& n, Pred&& pred ) const + { + return pred( color( n ) ); + } + + /*! \brief Evaluates a predicate on the colors of two nodes */ + template + bool eval_color( node const& a, node const& b, Pred&& pred ) const + { + return pred( color( a ), color( b ) ); + } + + /*! \brief Evaluates a predicate on the colors of the fanins of a node */ + template + bool eval_fanins_color( node const& n, Pred&& pred ) const + { + bool result = true; + this->foreach_fanin( n, [&]( signal const& fi ){ + if ( !pred( color( this->get_node( fi ) ) ) ) + { + result = false; + return false; + } + return true; + }); + return result; + } + +protected: + uint32_t value{0}; +}; /* color_view */ + +/*!\brief Manager view for traversal IDs (out-of-place storage). + * + * Traversal IDs, called colors, are unsigned integers that can be + * assigned to nodes. The corresponding values are stored + * out-of-place in this view. + */ +template +class out_of_place_color_view : public Ntk +{ +public: + using storage = typename Ntk::storage; + using node = typename Ntk::node; + using signal = typename Ntk::signal; + +public: + explicit out_of_place_color_view( Ntk const& ntk ) + : Ntk( ntk ) + , values( ntk.size() ) + { + static_assert( is_network_type_v, "Ntk is not a network type" ); + } + + uint32_t new_color() + { + return ++value; + } + + uint32_t current_color() const + { + return value; + } + + void clear( uint32_t color = 0 ) const + { + std::for_each( std::begin( values ), std::end( values ), + [color]( auto& v ) { v = color; } ); + } + + auto color( node const& n ) const + { + return values[n]; + } + + void paint( node const& n ) const + { + values[n] = value; + } + + void paint( node const& n, uint32_t color ) const + { + values[n] = color; + } + + void paint( node const& n, node const& other ) const + { + values[n] = values[other]; + } + + /*! \brief Evaluates a predicate on the color of a node */ + template + bool eval_color( node const& n, Pred&& pred ) const + { + return pred( color( n ) ); + } + + /*! \brief Evaluates a predicate on the colors of two nodes */ + template + bool eval_color( node const& a, node const& b, Pred&& pred ) const + { + return pred( color( a ), color( b ) ); + } + + /*! \brief Evaluates a predicate on the colors of the fanins of a node */ + template + bool eval_fanins_color( node const& n, Pred&& pred ) const + { + bool result = true; + this->foreach_fanin( n, [&]( signal const& fi ){ + if ( !pred( color( this->get_node( fi ) ) ) ) + { + result = false; + return false; + } + return true; + }); + return result; + } + +protected: + mutable std::vector values; + uint32_t value{0}; +}; /* out_of_place_color_view */ + +} /* mockturtle */ diff --git a/test/views/color_view.cpp b/test/views/color_view.cpp new file mode 100644 index 000000000..be2fa105b --- /dev/null +++ b/test/views/color_view.cpp @@ -0,0 +1,139 @@ +#include + +#include +#include +#include + +using namespace mockturtle; + +TEST_CASE( "in-place color view", "[color_view]" ) +{ + aig_network _aig; + const auto a = _aig.create_pi(); + const auto b = _aig.create_pi(); + const auto c = _aig.create_pi(); + const auto d = _aig.create_pi(); + const auto e = _aig.create_pi(); + + const auto f1 = _aig.create_and( a, b ); + const auto f2 = _aig.create_and( c, d ); + const auto f3 = _aig.create_and( f1, f2 ); + const auto f4 = _aig.create_and( e, f2 ); + const auto f5 = _aig.create_and( f1, f3 ); + const auto f6 = _aig.create_and( f2, f3 ); + const auto f7 = _aig.create_and( f5, f6 ); + const auto f8 = _aig.create_and( f4, f7 ); + _aig.create_po( f8 ); + + color_view aig{_aig}; + + auto const white = aig.new_color(); + auto const yellow = aig.new_color(); + CHECK( yellow > white ); + auto const red = aig.new_color(); + CHECK( red > white ); + + /* assign some colors: f5 is white, f1 is yellow, and f3 is in the color of f1 */ + aig.paint( aig.get_node( f5 ), white ); + aig.paint( aig.get_node( f1 ), yellow ); + aig.paint( aig.get_node( f3 ), aig.get_node( f1 ) ); + + /* f1 and f3 have the same color */ + CHECK( aig.eval_color( aig.get_node( f1 ), aig.get_node( f3 ), + [&]( auto c0, auto c1 ){ return c0 == c1; } ) ); + + /* f1 and f5 have different colors */ + CHECK( aig.eval_color( aig.get_node( f1 ), aig.get_node( f5 ), + [&]( auto c0, auto c1 ){ return c0 != c1; } ) ); + + /* f5 is at least white */ + CHECK( aig.eval_color( aig.get_node( f5 ), + [&]( auto color ){ return color >= white; } ) ); + + /* f5 is not yellow */ + CHECK( aig.eval_color( aig.get_node( f5 ), + [&]( auto color ){ return color != yellow; } ) ); + + /* the fanin's of f5 are at least white */ + CHECK( aig.eval_fanins_color( aig.get_node( f5 ), + [&]( auto color ){ return color >= white; } ) ); + + /* the fanins of f5 are yellow */ + CHECK( aig.eval_fanins_color( aig.get_node( f5 ), + [&]( auto color ){ return color == yellow; } ) ); + + /* at least one fanin of f5 is not red */ + CHECK( aig.eval_fanins_color( aig.get_node( f5 ), + [&]( auto color ){ return color != red; } ) ); + + /* colors are stored in the visited flags */ + CHECK( aig.visited( aig.get_node( f5 ) ) == white ); + CHECK( aig.visited( aig.get_node( f1 ) ) == yellow ); + CHECK( aig.visited( aig.get_node( f3 ) ) == yellow ); +} + +TEST_CASE( "out-of-place color view", "[color_view]" ) +{ + aig_network _aig; + const auto a = _aig.create_pi(); + const auto b = _aig.create_pi(); + const auto c = _aig.create_pi(); + const auto d = _aig.create_pi(); + const auto e = _aig.create_pi(); + + const auto f1 = _aig.create_and( a, b ); + const auto f2 = _aig.create_and( c, d ); + const auto f3 = _aig.create_and( f1, f2 ); + const auto f4 = _aig.create_and( e, f2 ); + const auto f5 = _aig.create_and( f1, f3 ); + const auto f6 = _aig.create_and( f2, f3 ); + const auto f7 = _aig.create_and( f5, f6 ); + const auto f8 = _aig.create_and( f4, f7 ); + _aig.create_po( f8 ); + + out_of_place_color_view aig{_aig}; + + auto const white = aig.new_color(); + auto const yellow = aig.new_color(); + CHECK( yellow > white ); + auto const red = aig.new_color(); + CHECK( red > white ); + + /* assign some colors: f5 is white, f1 is yellow, and f3 is in the color of f1 */ + aig.paint( aig.get_node( f5 ), white ); + aig.paint( aig.get_node( f1 ), yellow ); + aig.paint( aig.get_node( f3 ), aig.get_node( f1 ) ); + + /* f1 and f3 have the same color */ + CHECK( aig.eval_color( aig.get_node( f1 ), aig.get_node( f3 ), + [&]( auto c0, auto c1 ){ return c0 == c1; } ) ); + + /* f1 and f5 have different colors */ + CHECK( aig.eval_color( aig.get_node( f1 ), aig.get_node( f5 ), + [&]( auto c0, auto c1 ){ return c0 != c1; } ) ); + + /* f5 is at least white */ + CHECK( aig.eval_color( aig.get_node( f5 ), + [&]( auto color ){ return color >= white; } ) ); + + /* f5 is not yellow */ + CHECK( aig.eval_color( aig.get_node( f5 ), + [&]( auto color ){ return color != yellow; } ) ); + + /* the fanin's of f5 are at least white */ + CHECK( aig.eval_fanins_color( aig.get_node( f5 ), + [&]( auto color ){ return color >= white; } ) ); + + /* the fanins of f5 are yellow */ + CHECK( aig.eval_fanins_color( aig.get_node( f5 ), + [&]( auto color ){ return color == yellow; } ) ); + + /* at least one fanin of f5 is not red */ + CHECK( aig.eval_fanins_color( aig.get_node( f5 ), + [&]( auto color ){ return color != red; } ) ); + + /* visited flags have not been affected by assigning colors */ + CHECK( aig.visited( aig.get_node( f5 ) ) == 0u ); + CHECK( aig.visited( aig.get_node( f1 ) ) == 0u ); + CHECK( aig.visited( aig.get_node( f3 ) ) == 0u ); +} From e2049e41d38ceaaea5950284457f93cd1d45902e Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 15:58:43 +0200 Subject: [PATCH 20/30] integrate color_view. --- include/mockturtle/utils/window_utils.hpp | 62 ++-- include/mockturtle/views/color_view.hpp | 32 +- test/views/window_view.cpp | 341 +++++++--------------- 3 files changed, 157 insertions(+), 278 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index c3b36fc18..898be71cb 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -144,8 +144,8 @@ inline std::vector collect_nodes( Ntk const& ntk, /*! \brief Identify inputs using reference counting */ -template -std::vector collect_inputs( Ntk const& ntk, std::vector const& nodes, ColorMap& colors ) +template +std::vector collect_inputs( Ntk const& ntk, std::vector const& nodes ) { using node = typename Ntk::node; using signal = typename Ntk::signal; @@ -153,7 +153,7 @@ std::vector collect_inputs( Ntk const& ntk, std::vector collect_inputs( Ntk const& ntk, std::vector collect_inputs( Ntk const& ntk, std::vector collect_inputs( Ntk const& ntk, std::vector + template inline std::vector collect_outputs( Ntk const& ntk, std::vector const& inputs, std::vector const& nodes, - std::vector& refs, - ColorMap& colors ) + std::vector& refs ) { using signal = typename Ntk::signal; @@ -219,13 +217,13 @@ inline std::vector collect_outputs( Ntk const& ntk, /* mark the inputs visited */ for ( auto const& i : inputs ) { - colors.paint( i ); + ntk.paint( i ); } /* reference fanins of nodes */ for ( auto const& n : nodes ) { - if ( colors.colored( n ) ) + if ( ntk.eval_color( n, [&ntk]( auto c ){ return c == ntk.current_color(); } ) ) { continue; } @@ -240,7 +238,7 @@ inline std::vector collect_outputs( Ntk const& ntk, the node has fanout outside of the window is an output */ for ( const auto& n : nodes ) { - if ( colors.colored( n ) ) + if ( ntk.eval_color( n, [&ntk]( auto c ){ return c == ntk.current_color(); } ) ) { continue; } @@ -254,7 +252,7 @@ inline std::vector collect_outputs( Ntk const& ntk, /* dereference fanins of nodes */ for ( auto const& n : nodes ) { - if ( colors.colored( n ) ) + if ( ntk.eval_color( n, [&ntk]( auto c ){ return c == ntk.current_color(); } ) ) { continue; } @@ -277,7 +275,6 @@ inline std::vector collect_outputs( Ntk const& ntk, * * \param ntk A network * \param inputs Input nodes - * \param colors Auxiliar data structure to mark nodes * \return True if and only if the inputs form a trivial cut that * cannot be further extended, e.g., when the cut only * consists of PIs. @@ -290,9 +287,8 @@ inline std::vector collect_outputs( Ntk const& ntk, * - `foreach_fanin` * - `get_node` */ -template -bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs, - ColorMap& colors ) +template +bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs ) { using node = typename Ntk::node; using signal = typename Ntk::signal; @@ -300,7 +296,7 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input /* mark all inputs */ for ( auto const& i : inputs ) { - colors.paint( i ); + ntk.paint( i ); } /* we call a set of inputs (= a cut) trivial if all nodes are either @@ -326,7 +322,7 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input node const n = ntk.get_node( fi ); trivial_cut = false; - if ( !colors.colored( n ) ) + if ( !ntk.eval_color( n, [&ntk]( auto c ){ return c == ntk.current_color(); } ) ) { ++count_fanin_outside; ep = n; @@ -432,17 +428,15 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: * \param ntk A network * \param inputs Input nodes * \param input_limit Size limit for the maximum number of input nodes - * \param colors Auxiliar data structure to mark nodes */ -template -void expand_towards_tfi( Ntk const& ntk, std::vector& inputs, uint32_t input_limit, - ColorMap& colors ) +template +void expand_towards_tfi( Ntk const& ntk, std::vector& inputs, uint32_t input_limit ) { using node = typename Ntk::node; static constexpr uint32_t const MAX_ITERATIONS{5u}; - if ( expand0_towards_tfi( ntk, inputs, colors ) ) + if ( expand0_towards_tfi( ntk, inputs ) ) { return; } @@ -454,8 +448,8 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs { node const n = detail::select_next_fanin_to_expand_tfi( ntk, inputs ); inputs.push_back( n ); - colors.paint( n ); - trivial_cut = expand0_towards_tfi( ntk, inputs, colors ); + ntk.paint( n ); + trivial_cut = expand0_towards_tfi( ntk, inputs ); if ( inputs.size() <= input_limit ) { @@ -599,7 +593,6 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * \param ntk A network * \param inputs Input nodes of a window * \param nodes Inner nodes of a window - * \param colors Auxiliar data structure to mark nodes * * **Required network functions:** * - `foreach_fanin` @@ -608,10 +601,14 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * - `level` * - `is_constant` * - `is_ci` + * - `depth` + * - `paint` + * - `eval_color` + * - `current_color` + * - `eval_fanins_color` */ -template -void levelized_expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes, - ColorMap& colors ) +template +void levelized_expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) { using node = typename Ntk::node; @@ -630,7 +627,7 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector_storage->data.trav_id; + // return ++value; } /*! \brief Returns the current color */ uint32_t current_color() const { - return value; + return this->_storage->data.trav_id; + // return value; } /*! \brief Assigns all nodes to `color` */ - void clear( uint32_t color = 0 ) const + void clear_colors( uint32_t color = 0 ) const { std::for_each( this->_storage->nodes.begin(), this->_storage->nodes.end(), [color]( auto& n ) { n.data[1].h1 = color; } ); @@ -81,10 +84,16 @@ class color_view : public Ntk return this->_storage->nodes[n].data[1].h1; } + /*! \brief Returns the color of a node */ + auto color( signal const& n ) const + { + return this->_storage->nodes[this->get_node( n )].data[1].h1; + } + /*! \brief Assigns the current color to a node */ void paint( node const& n ) const { - this->_storage->nodes[n].data[1].h1 = value; + this->_storage->nodes[n].data[1].h1 = current_color(); } /*! \brief Assigns `color` to a node */ @@ -130,7 +139,7 @@ class color_view : public Ntk } protected: - uint32_t value{0}; + // mutable uint32_t value{0}; }; /* color_view */ /*!\brief Manager view for traversal IDs (out-of-place storage). @@ -155,7 +164,7 @@ class out_of_place_color_view : public Ntk static_assert( is_network_type_v, "Ntk is not a network type" ); } - uint32_t new_color() + uint32_t new_color() const { return ++value; } @@ -165,7 +174,7 @@ class out_of_place_color_view : public Ntk return value; } - void clear( uint32_t color = 0 ) const + void clear_colors( uint32_t color = 0 ) const { std::for_each( std::begin( values ), std::end( values ), [color]( auto& v ) { v = color; } ); @@ -176,6 +185,11 @@ class out_of_place_color_view : public Ntk return values[n]; } + auto color( signal const& n ) const + { + return values[this->get_node( n )]; + } + void paint( node const& n ) const { values[n] = value; @@ -223,7 +237,7 @@ class out_of_place_color_view : public Ntk protected: mutable std::vector values; - uint32_t value{0}; + mutable uint32_t value{0}; }; /* out_of_place_color_view */ } /* mockturtle */ diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 2751be5e6..2698f1f53 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -6,145 +6,10 @@ #include #include #include +#include using namespace mockturtle; -template -struct colors_impl1 -{ -public: - using node = typename Ntk::node; - using signal = typename Ntk::signal; - -public: - colors_impl1( Ntk const& ntk ) - : ntk( ntk ) - { - ntk.incr_trav_id(); - } - - void new_color() - { - ntk.incr_trav_id(); - } - - uint32_t color() const - { - return ntk.trav_id(); - } - - bool colored( node const& n ) const - { - return ntk.visited( n ) == ntk.trav_id(); - } - - bool colored( node const& n, uint32_t k ) const - { - return ntk.visited( n ) >= ntk.trav_id() - k; - } - - bool same_color( node const& a, node const& b ) const - { - return ntk.visited( a ) == ntk.visited( b ); - } - - bool fanins_colored( node const& n ) const - { - bool result = true; - ntk.foreach_fanin( n, [&]( signal const& fi ){ - if ( !colored( ntk.get_node( fi ) ) ) - { - result = false; - return false; - } - return true; - }); - return result; - } - - void paint( node const& n ) - { - ntk.set_visited( n, ntk.trav_id() ); - } - - void paint( node const& n, node const& a ) - { - ntk.set_visited( n, ntk.visited( a ) ); - } - -protected: - Ntk const& ntk; -}; - -template -struct colors_impl2 -{ -public: - using node = typename Ntk::node; - using signal = typename Ntk::signal; - -public: - colors_impl2( Ntk const& ntk ) - : ntk( ntk ) - , values( ntk.size() ) - {} - - void new_color() - { - ++value; - } - - uint32_t color() const - { - return value; - } - - bool colored( node const& n ) const - { - return values[n] == value; - } - - bool colored( node const& n, uint32_t k ) const - { - return values[n] >= value - k; - } - - bool same_color( node const& a, node const& b ) const - { - return values[a] == values[b]; - } - - bool fanins_colored( node const& n ) const - { - bool result = true; - ntk.foreach_fanin( n, [&]( signal const& fi ){ - if ( !colored( ntk.get_node( fi ) ) ) - { - result = false; - return false; - } - return true; - }); - return result; - } - - void paint( node const& n ) - { - values[n] = value; - } - - void paint( node const& n, node const& a ) - { - values[n] = values[a]; - ntk.set_visited( n, ntk.visited( a ) ); - } - -protected: - Ntk const& ntk; - std::vector values; - uint32_t value{1}; -}; - template std::vector collect_fanin_nodes( Ntk const& ntk, typename Ntk::node const& n ) { @@ -389,9 +254,8 @@ TEST_CASE( "expand towards tfo", "[window_view]" ) }); } - template -class create_window_impl2 +class create_window_impl { public: using node = typename Ntk::node; @@ -403,15 +267,14 @@ class create_window_impl2 std::vector nodes; std::vector outputs; }; - + protected: /* constant node used to denotes invalid window element */ static constexpr node INVALID_NODE{0}; public: - create_window_impl2( Ntk const& ntk ) + create_window_impl( Ntk const& ntk ) : ntk( ntk ) - , colors( ntk ) , path( ntk.size() ) , refs( ntk.size() ) { @@ -427,24 +290,23 @@ class create_window_impl2 return std::nullopt; } - /* collect the fanins for these nodes */ - colors.new_color(); - std::vector inputs = collect_inputs( ntk, *nodes, colors ); + /* collect the fanins for these nodes */ + ntk.new_color(); + std::vector inputs = collect_inputs( ntk, *nodes ); /* expand the nodes towards the TFI */ - colors.new_color(); - expand_towards_tfi( ntk, inputs, 6u, colors ); + ntk.new_color(); + expand_towards_tfi( ntk, inputs, 6u ); /* expand the nodes towards the TFO */ - colors.new_color(); - expand_towards_tfi( ntk, inputs, 6u, colors ); - levelized_expand_towards_tfo( ntk, inputs, *nodes, colors ); + ntk.new_color(); + levelized_expand_towards_tfo( ntk, inputs, *nodes ); - /* collect the nodes with fanout outside of nodes */ - colors.new_color(); - std::vector outputs = collect_outputs( ntk, inputs, *nodes, refs, colors ); + /* collect the nodes with fanout outside of nodes */ + ntk.new_color(); + std::vector outputs = collect_outputs( ntk, inputs, *nodes, refs ); - /* sort nodes */ + /* top. sort nodes */ std::sort( std::begin( inputs ), std::end( inputs ) ); std::sort( std::begin( *nodes ), std::end( *nodes ) ); @@ -455,14 +317,12 @@ class create_window_impl2 std::optional> identify_reconvergence( node const& pivot, uint64_t num_iterations ) { visited.clear(); - ntk.foreach_fanin( pivot, [&]( signal const& fi ){ - colors.new_color(); - + uint32_t const color = ntk.new_color(); node const& n = ntk.get_node( fi ); - colors.paint( n ); path[n] = INVALID_NODE; visited.push_back( n ); + ntk.paint( n, color ); }); uint64_t start{0}; @@ -499,20 +359,20 @@ class create_window_impl2 return true; /* next */ } - if ( colors.colored( n, ntk.max_fanin_size - 1 ) && - colors.colored( fi_node, ntk.max_fanin_size - 1 ) && - !colors.same_color( n, fi_node ) ) + if ( ntk.eval_color( n, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } )&& + ntk.eval_color( fi_node, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } ) && + ntk.eval_color( n, fi_node, []( auto c0, auto c1 ){ return c0 != c1; } ) ) { meet = fi_node; return false; } - if ( colors.colored( fi_node, ntk.max_fanin_size - 1 ) ) + if ( ntk.eval_color( fi_node, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } ) ) { return true; /* next */ } - colors.paint( fi_node, n ); + ntk.paint( fi_node, n ); path[fi_node] = n; visited.push_back( fi_node ); return true; /* next */ @@ -536,13 +396,12 @@ class create_window_impl2 return; } - assert( colors.same_color( n, pred ) ); + assert( ntk.eval_color( n, pred, []( auto c0, auto c1 ){ return c0 == c1; } ) ); gather_nodes_recursively( pred ); } protected: Ntk const& ntk; - colors_impl1 colors; std::vector visited; std::vector path; std::vector refs; @@ -552,25 +411,25 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) { using node = typename aig_network::node; - aig_network aig; - auto const a = aig.create_pi(); - auto const b = aig.create_pi(); - auto const c = aig.create_pi(); - auto const d = aig.create_pi(); - auto const f1 = aig.create_and( b, c ); - auto const f2 = aig.create_and( b, f1 ); - auto const f3 = aig.create_and( a, f2 ); - auto const f4 = aig.create_and( d, f2 ); - auto const f5 = aig.create_and( f3, f4 ); - aig.create_po( f5 ); + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); - colors_impl1 colors( aig ); + color_view aig{_aig}; { /* a cut that can be expanded without increasing cut-size */ std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); CHECK( trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -578,12 +437,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { - colors.new_color(); + aig.new_color(); /* a cut that cannot be expanded without increasing cut-size */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -591,12 +450,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { - colors.new_color(); + aig.new_color(); /* a cut that can be moved towards the PIs */ std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -604,12 +463,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { - colors.new_color(); + aig.new_color(); /* the cut { f3, f5 } can be simplified to { f3, f4 } */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -617,12 +476,12 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) } { - colors.new_color(); + aig.new_color(); /* the cut { f4, f5 } also can be simplified to { f3, f4 } */ std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; - bool const trivial_cut = expand0_towards_tfi( aig, inputs, colors ); + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); CHECK( !trivial_cut ); std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -634,46 +493,46 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) { using node = typename aig_network::node; - aig_network aig; - auto const a = aig.create_pi(); - auto const b = aig.create_pi(); - auto const c = aig.create_pi(); - auto const d = aig.create_pi(); - auto const f1 = aig.create_and( b, c ); - auto const f2 = aig.create_and( b, f1 ); - auto const f3 = aig.create_and( a, f2 ); - auto const f4 = aig.create_and( d, f2 ); - auto const f5 = aig.create_and( f3, f4 ); - aig.create_po( f5 ); + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); - colors_impl1 colors( aig ); + color_view aig{_aig}; { /* expand from { f5 } to 4-cut { a, b, c, d } */ std::vector inputs{aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 4u, colors ); + expand_towards_tfi( aig, inputs, 4u ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); } { - colors.new_color(); + aig.new_color(); /* expand from { f3, f5 } to 3-cut { a, b, f2 } */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u, colors ); + expand_towards_tfi( aig, inputs, 3u ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); } { - colors.new_color(); + aig.new_color(); /* expand from { f4, f5 } to 3-cut { a, b, f2 } */ std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u, colors ); + expand_towards_tfi( aig, inputs, 3u ); std::sort( std::begin( inputs ), std::end( inputs ) ); CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); @@ -684,37 +543,36 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) { using node = typename aig_network::node; - aig_network aig; - auto const a = aig.create_pi(); - auto const b = aig.create_pi(); - auto const c = aig.create_pi(); - auto const d = aig.create_pi(); - auto const f1 = aig.create_and( b, c ); - auto const f2 = aig.create_and( b, f1 ); - auto const f3 = aig.create_and( a, f2 ); - auto const f4 = aig.create_and( d, f2 ); - auto const f5 = aig.create_and( f3, f4 ); - aig.create_po( f5 ); - - std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; - - fanout_view fanout_aig{aig}; + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); + + std::vector inputs{_aig.get_node( a ), _aig.get_node( b ), _aig.get_node( c ), _aig.get_node( d )}; + + fanout_view fanout_aig{_aig}; depth_view depth_aig{fanout_aig}; + color_view aig{depth_aig}; { std::vector nodes; - expand_towards_tfo( depth_aig, inputs, nodes ); + expand_towards_tfo( aig, inputs, nodes ); std::sort( std::begin( nodes ), std::end( nodes ) ); CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 ), aig.get_node( f5 )} ); } - colors_impl1 colors( aig ); - { std::vector nodes; - levelized_expand_towards_tfo( depth_aig, inputs, nodes, colors ); + levelized_expand_towards_tfo( aig, inputs, nodes ); std::sort( std::begin( nodes ), std::end( nodes ) ); CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f4 )} ); @@ -723,23 +581,32 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) TEST_CASE( "make a window", "[create_window]" ) { - aig_network aig; - auto const a = aig.create_pi(); - auto const b = aig.create_pi(); - auto const c = aig.create_pi(); - auto const d = aig.create_pi(); - auto const f1 = aig.create_and( b, c ); - auto const f2 = aig.create_and( b, f1 ); - auto const f3 = aig.create_and( a, f2 ); - auto const f4 = aig.create_and( d, f2 ); - auto const f5 = aig.create_and( f3, f4 ); - aig.create_po( f5 ); - - fanout_view fanout_aig{aig}; + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); + + fanout_view fanout_aig{_aig}; depth_view depth_aig{fanout_aig}; - - create_window_impl2 windowing( depth_aig ); - auto info = windowing.run( depth_aig.get_node( f5 ) ); + color_view aig{depth_aig}; + + /* FIXME: fix mismatch between color_view.value and trav_id */ + // while ( aig.trav_id() > aig.current_color() ) + // { + // aig.new_color(); + // } + // assert( aig.trav_id() == aig.current_color() ); + + create_window_impl windowing( aig ); + auto info = windowing.run( aig.get_node( f5 ) ); + CHECK( info ); if ( info ) { window_view win( aig, info->inputs, info->outputs, info->nodes ); From c99fdb115a6593b31b0b0a14aab97665198b8d88 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 15 Oct 2020 10:33:37 +0200 Subject: [PATCH 21/30] window_utils: allows first allocate a new color. --- include/mockturtle/utils/window_utils.hpp | 2 +- test/views/window_view.cpp | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 898be71cb..ea6f7f46e 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -322,7 +322,7 @@ bool expand0_towards_tfi( Ntk const& ntk, std::vector& input node const n = ntk.get_node( fi ); trivial_cut = false; - if ( !ntk.eval_color( n, [&ntk]( auto c ){ return c == ntk.current_color(); } ) ) + if ( ntk.eval_color( n, [&ntk]( auto c ){ return c != ntk.current_color(); } ) ) { ++count_fanin_outside; ep = n; diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 2698f1f53..c8597a0d5 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -424,6 +424,7 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) _aig.create_po( f5 ); color_view aig{_aig}; + aig.new_color(); { /* a cut that can be expanded without increasing cut-size */ @@ -506,6 +507,7 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) _aig.create_po( f5 ); color_view aig{_aig}; + aig.new_color(); { /* expand from { f5 } to 4-cut { a, b, c, d } */ @@ -560,6 +562,7 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) fanout_view fanout_aig{_aig}; depth_view depth_aig{fanout_aig}; color_view aig{depth_aig}; + aig.new_color(); { std::vector nodes; @@ -596,13 +599,7 @@ TEST_CASE( "make a window", "[create_window]" ) fanout_view fanout_aig{_aig}; depth_view depth_aig{fanout_aig}; color_view aig{depth_aig}; - - /* FIXME: fix mismatch between color_view.value and trav_id */ - // while ( aig.trav_id() > aig.current_color() ) - // { - // aig.new_color(); - // } - // assert( aig.trav_id() == aig.current_color() ); + aig.new_color(); create_window_impl windowing( aig ); auto info = windowing.run( aig.get_node( f5 ) ); From 04f7dcb2eab32510752ad4f113e2f3a245d302c3 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 15 Oct 2020 10:52:28 +0200 Subject: [PATCH 22/30] window_utils: always first allocate a new color. --- include/mockturtle/utils/window_utils.hpp | 6 +++--- test/views/window_view.cpp | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index ea6f7f46e..6b4cb5b30 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -449,8 +449,8 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs node const n = detail::select_next_fanin_to_expand_tfi( ntk, inputs ); inputs.push_back( n ); ntk.paint( n ); - trivial_cut = expand0_towards_tfi( ntk, inputs ); + trivial_cut = expand0_towards_tfi( ntk, inputs ); if ( inputs.size() <= input_limit ) { best_cut = inputs; @@ -623,7 +623,7 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector nodes; levelized_expand_towards_tfo( aig, inputs, nodes ); From 0be74a1f62b14fae015f948811928e7de2ae956f Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 15 Oct 2020 12:05:34 +0200 Subject: [PATCH 23/30] tighter integration of color_view. --- include/mockturtle/algorithms/dont_cares.hpp | 11 +- include/mockturtle/utils/window_utils.hpp | 108 ++++++++++++------- include/mockturtle/views/color_view.hpp | 1 + test/views/window_view.cpp | 67 ++++++------ 4 files changed, 109 insertions(+), 78 deletions(-) diff --git a/include/mockturtle/algorithms/dont_cares.hpp b/include/mockturtle/algorithms/dont_cares.hpp index 1dd068ea0..6ba25b838 100644 --- a/include/mockturtle/algorithms/dont_cares.hpp +++ b/include/mockturtle/algorithms/dont_cares.hpp @@ -44,6 +44,7 @@ #include "../views/fanout_view.hpp" #include "../views/topo_view.hpp" #include "../views/window_view.hpp" +#include "../views/color_view.hpp" #include #include @@ -74,9 +75,10 @@ kitty::dynamic_truth_table satisfiability_dont_cares( Ntk const& ntk, std::vecto fanout_view fanout_ntk{ntk}; fanout_ntk.clear_visited(); + color_view color_ntk{fanout_ntk}; - std::vector> gates{collect_nodes( ntk, extended_leaves, leaves )}; - window_view> window_ntk{fanout_ntk, extended_leaves, leaves, gates}; + std::vector> gates{collect_nodes( color_ntk, extended_leaves, leaves )}; + window_view window_ntk{color_ntk, extended_leaves, leaves, gates}; default_simulator sim( window_ntk.num_pis() ); const auto tts = simulate_nodes( window_ntk, sim ); @@ -111,9 +113,10 @@ kitty::dynamic_truth_table observability_dont_cares( Ntk const& ntk, node c { fanout_view fanout_ntk{ntk}; fanout_ntk.clear_visited(); + color_view color_ntk{fanout_ntk}; - std::vector> gates{collect_nodes( ntk, leaves, roots )}; - window_view> window_ntk{fanout_ntk, leaves, roots, gates}; + std::vector> gates{collect_nodes( color_ntk, leaves, roots )}; + window_view window_ntk{color_ntk, leaves, roots, gates}; default_simulator sim( window_ntk.num_pis() ); unordered_node_map node_to_value0( ntk ); diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 6b4cb5b30..04805b75f 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -46,11 +46,11 @@ inline void collect_nodes_recur( Ntk const& ntk, typename Ntk::node const& n, st { using signal = typename Ntk::signal; - if ( ntk.visited( n ) == ntk.trav_id() ) + if ( ntk.eval_color( n, [&]( auto c ){ return c == ntk.current_color(); } ) ) { return; } - ntk.set_visited( n, ntk.trav_id() ); + ntk.paint( n ); ntk.foreach_fanin( n, [&]( signal const& fi ){ collect_nodes_recur( ntk, ntk.get_node( fi ), nodes ); @@ -70,13 +70,15 @@ inline void collect_nodes_recur( Ntk const& ntk, typename Ntk::node const& n, st * The output set has to be chosen in a way such that every path from * PIs to outputs passes through at least one input. * + * Uses a new color. + * * **Required network functions:** + * - `current_color` + * - `eval_color` * - `foreach_fanin` * - `get_node` - * - `incr_trav_id` - * - `set_visited` - * - `trav_id` - * - `visited` + * - `new_color` + * - `paint` */ template>> inline std::vector collect_nodes( Ntk const& ntk, @@ -105,13 +107,15 @@ inline std::vector collect_nodes( Ntk const& ntk, * The output set has to be chosen in a way such that every path from * PIs to outputs passes through at least one input. * + * Uses a new color. + * * **Required network functions:** + * - `current_color` + * - `eval_color` * - `foreach_fanin` * - `get_node` - * - `incr_trav_id` - * - `set_visited` - * - `trav_id` - * - `visited` + * - `new_color` + * - `paint` */ template inline std::vector collect_nodes( Ntk const& ntk, @@ -120,17 +124,16 @@ inline std::vector collect_nodes( Ntk const& ntk, { using node = typename Ntk::node; - /* create a new traversal ID */ - ntk.incr_trav_id(); + ntk.new_color(); /* mark inputs visited */ for ( auto const& i : inputs ) { - if ( ntk.visited( i ) == ntk.trav_id() ) + if ( ntk.eval_color( i, [&]( auto c ){ return c == ntk.current_color(); } ) ) { continue; } - ntk.set_visited( i, ntk.trav_id() ); + ntk.paint( i ); } /* recursively collect all nodes in between inputs and outputs */ @@ -143,13 +146,25 @@ inline std::vector collect_nodes( Ntk const& ntk, } /*! \brief Identify inputs using reference counting + * + * Uses a new_color. + * + * **Required network functions:** + * - `current_color` + * - `eval_color` + * - `foreach_fanin` + * - `get_node` + * - `new_color` + * - `paint` */ template std::vector collect_inputs( Ntk const& ntk, std::vector const& nodes ) { using node = typename Ntk::node; using signal = typename Ntk::signal; - + + ntk.new_color(); + /* mark all nodes with a new color */ for ( const auto& n : nodes ) { @@ -193,6 +208,8 @@ std::vector collect_inputs( Ntk const& ntk, std::vector collect_inputs( Ntk const& ntk, std::vector +template inline std::vector collect_outputs( Ntk const& ntk, std::vector const& inputs, std::vector const& nodes, @@ -268,24 +285,27 @@ inline std::vector collect_outputs( Ntk const& ntk, /*! \brief Performs in-place zero-cost expansion of a set of nodes towards TFI * - * The algorithm potentially derives a different cut of the same size + * The algorithm attempts to derive a different cut of the same size * that is closer to the network's PIs. This expansion towards TFI is * called zero-cost because it merges nodes only if the number of * inputs does not increase. * + * Uses the current color to mark nodes. Only nodes not painted with + * the current color are considered for expanding the cut. + * * \param ntk A network * \param inputs Input nodes * \return True if and only if the inputs form a trivial cut that * cannot be further extended, e.g., when the cut only * consists of PIs. * - * On termination, `colors[i] == color` if `i \in inputs`. However, - * previous inputs are also marked. - * * **Required network functions:** - * - `size` + * - `current_color` + * - `eval_color` * - `foreach_fanin` * - `get_node` + * - `paint` + * - `size` */ template bool expand0_towards_tfi( Ntk const& ntk, std::vector& inputs ) @@ -425,6 +445,8 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: * procedure allows a temporary increase of `inputs` beyond the * `input_limit` for at most `MAX_ITERATIONS`. * + * Uses a new color. + * * \param ntk A network * \param inputs Input nodes * \param input_limit Size limit for the maximum number of input nodes @@ -436,6 +458,7 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs static constexpr uint32_t const MAX_ITERATIONS{5u}; + ntk.new_color(); if ( expand0_towards_tfi( ntk, inputs ) ) { return; @@ -468,11 +491,15 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs * fanouts that are supported by the window until a fixed-point is * reached. * + * Uses a new color. + * * \param ntk A network * \param inputs Input nodes of a window * \param nodes Inner nodes of a window * * **Required network functions:** + * - `current_color` + * - `eval_color` * - `foreach_fanin` * - `foreach_fanout` * - `get_node` @@ -481,6 +508,9 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs * - `set_visited` * - `trav_id` * - `visited` + * - `eval_color` + * - `current_color` + * - `new_color` */ template void expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) @@ -495,8 +525,8 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& { return false; } - /* skip all nodes that are already in nodex */ - if ( ntk.visited( fo ) == ntk.trav_id() ) + /* skip all nodes that are already in nodes */ + if ( ntk.eval_color( fo, [&]( auto c ){ return c == ntk.current_color(); } ) ) { return true; } @@ -506,24 +536,21 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& }; /* create a new traversal ID */ - ntk.incr_trav_id(); + ntk.new_color(); /* mark the inputs visited */ - for ( auto const& i : inputs ) - { - ntk.set_visited( i, ntk.trav_id() ); - } + std::for_each( std::begin( inputs ), std::end( inputs ), + [&ntk]( node const& n ){ ntk.paint( n ); } ); + /* mark the nodes visited */ - for ( const auto& n : nodes ) - { - ntk.set_visited( n, ntk.trav_id() ); - } + std::for_each( std::begin( nodes ), std::end( nodes ), + [&ntk]( node const& n ){ ntk.paint( n ); } ); /* collect all nodes that have fanouts not yet contained in nodes */ std::set eps; - for ( const auto& n : inputs ) + for ( const auto& i : inputs ) { - explore_fanouts( ntk, n, eps ); + explore_fanouts( ntk, i, eps ); } for ( const auto& n : nodes ) { @@ -541,7 +568,7 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& while ( it != std::end( eps ) ) { node const ep = *it; - if ( ntk.visited( ep ) == ntk.trav_id() ) + if ( ntk.eval_color( ep, [&]( auto c ){ return c == ntk.current_color(); } ) ) { it = eps.erase( it ); continue; @@ -550,7 +577,7 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& bool all_children_belong_to_window = true; ntk.foreach_fanin( ep, [&]( signal const& fi ){ node const child = ntk.get_node( fi ); - if ( ntk.visited( child ) != ntk.trav_id() ) + if ( ntk.eval_color( child, [&]( auto c ){ return c != ntk.current_color(); } ) ) { all_children_belong_to_window = false; return false; @@ -590,6 +617,8 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * level by level. Starting with those that are closest to the * inputs. * + * Uses a new color. + * * \param ntk A network * \param inputs Input nodes of a window * \param nodes Inner nodes of a window @@ -606,6 +635,7 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * - `eval_color` * - `current_color` * - `eval_fanins_color` + * - `new_color` */ template void levelized_expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) @@ -614,6 +644,8 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector> levels( ntk.depth() ); @@ -653,8 +685,8 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector>> auto color( signal const& n ) const { return this->_storage->nodes[this->get_node( n )].data[1].h1; diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 210968403..1c148bd7d 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -199,21 +199,23 @@ TEST_CASE( "create window view on AIG", "[window_view]" ) TEST_CASE( "collect nodes", "[window_view]" ) { - aig_network aig; - auto const a = aig.create_pi(); - auto const b = aig.create_pi(); - auto const c = aig.create_pi(); - auto const d = aig.create_pi(); - auto const f1 = aig.create_xor( a, b ); - auto const f2 = aig.create_xor( c, d ); - auto const f3 = aig.create_xor( f1, f2 ); - auto const f4 = aig.create_and( f1, f2 ); - aig.create_po( f3 ); - aig.create_po( f4 ); + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_xor( a, b ); + auto const f2 = _aig.create_xor( c, d ); + auto const f3 = _aig.create_xor( f1, f2 ); + auto const f4 = _aig.create_and( f1, f2 ); + _aig.create_po( f3 ); + _aig.create_po( f4 ); using node = typename aig_network::node; using signal = typename aig_network::signal; + color_view aig{_aig}; + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; std::vector outputs{f3, f4}; std::vector const gates{collect_nodes( aig, inputs, outputs )}; @@ -226,27 +228,28 @@ TEST_CASE( "collect nodes", "[window_view]" ) TEST_CASE( "expand towards tfo", "[window_view]" ) { - aig_network aig; - auto const a = aig.create_pi(); - auto const b = aig.create_pi(); - auto const c = aig.create_pi(); - auto const d = aig.create_pi(); - auto const f1 = aig.create_xor( a, b ); - auto const f2 = aig.create_xor( c, d ); - auto const f3 = aig.create_xor( f1, f2 ); - auto const f4 = aig.create_and( f1, f2 ); - aig.create_po( f3 ); - aig.create_po( f4 ); + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_xor( a, b ); + auto const f2 = _aig.create_xor( c, d ); + auto const f3 = _aig.create_xor( f1, f2 ); + auto const f4 = _aig.create_and( f1, f2 ); + _aig.create_po( f3 ); + _aig.create_po( f4 ); using node = typename aig_network::node; using signal = typename aig_network::signal; - fanout_view faig( aig ); + fanout_view faig{_aig}; + color_view aig{faig}; - std::vector inputs{faig.get_node( a ), faig.get_node( b ), faig.get_node( c ), faig.get_node( d )}; + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )}; std::vector outputs{f1}; - std::vector gates{collect_nodes( faig, inputs, outputs )}; - expand_towards_tfo( faig, inputs, gates ); + std::vector gates{collect_nodes( aig, inputs, outputs )}; + expand_towards_tfo( aig, inputs, gates ); CHECK( gates.size() == aig.num_gates() ); aig.foreach_gate( [&]( node const& n ){ @@ -424,9 +427,9 @@ TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) _aig.create_po( f5 ); color_view aig{_aig}; - aig.new_color(); - { + aig.new_color(); + /* a cut that can be expanded without increasing cut-size */ std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; @@ -507,7 +510,6 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) _aig.create_po( f5 ); color_view aig{_aig}; - aig.new_color(); { /* expand from { f5 } to 4-cut { a, b, c, d } */ @@ -519,8 +521,6 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) } { - aig.new_color(); - /* expand from { f3, f5 } to 3-cut { a, b, f2 } */ std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; expand_towards_tfi( aig, inputs, 3u ); @@ -530,8 +530,6 @@ TEST_CASE( "expand node set towards TFI", "[window_utils]" ) } { - aig.new_color(); - /* expand from { f4, f5 } to 3-cut { a, b, f2 } */ std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; expand_towards_tfi( aig, inputs, 3u ); @@ -562,7 +560,6 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) fanout_view fanout_aig{_aig}; depth_view depth_aig{fanout_aig}; color_view aig{depth_aig}; - aig.new_color(); { std::vector nodes; @@ -574,8 +571,6 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) } { - aig.new_color(); - std::vector nodes; levelized_expand_towards_tfo( aig, inputs, nodes ); From 695945d482d4b0984331611e1f896beb6dfc7677 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 15 Oct 2020 13:06:19 +0200 Subject: [PATCH 24/30] traits. --- include/mockturtle/traits.hpp | 105 ++++++++++++++++++++++++ include/mockturtle/views/color_view.hpp | 1 - test/views/color_view.cpp | 48 ++++++++++- test/views/fanout_view.cpp | 4 + 4 files changed, 156 insertions(+), 2 deletions(-) diff --git a/include/mockturtle/traits.hpp b/include/mockturtle/traits.hpp index bc0cb995e..e2c54f41e 100644 --- a/include/mockturtle/traits.hpp +++ b/include/mockturtle/traits.hpp @@ -1943,6 +1943,111 @@ template inline constexpr bool has_has_output_name_v = has_has_output_name::value; #pragma endregion +#pragma region has_new_color +template +struct has_new_color : std::false_type +{ +}; + +template +struct has_new_color().new_color() )>> : std::true_type +{ +}; + +template +inline constexpr bool has_new_color_v = has_new_color::value; +#pragma endregion + +#pragma region has_current_color +template +struct has_current_color : std::false_type +{ +}; + +template +struct has_current_color().current_color() )>> : std::true_type +{ +}; + +template +inline constexpr bool has_current_color_v = has_current_color::value; +#pragma endregion + +#pragma region has_clear_colors +template +struct has_clear_colors : std::false_type +{ +}; + +template +struct has_clear_colors().clear_colors( uint32_t() ) )>> : std::true_type +{ +}; + +template +inline constexpr bool has_clear_colors_v = has_clear_colors::value; +#pragma endregion + +#pragma region has_color +template +struct has_color : std::false_type +{ +}; + +template +struct has_color().color( std::declval>() ) )>> : std::true_type +{ +}; + +template +inline constexpr bool has_color_v = has_color::value; +#pragma endregion + +#pragma region has_paint +template +struct has_paint : std::false_type +{ +}; + +template +struct has_paint().paint( std::declval>() ) )>> : std::true_type +{ +}; + +template +inline constexpr bool has_paint_v = has_paint::value; +#pragma endregion + +#pragma region has_eval_color +template +struct has_eval_color : std::false_type +{ +}; + +template +struct has_eval_color().eval_color( std::declval>(), std::declval() ) )>> : std::true_type +{ +}; + +template +inline constexpr bool has_eval_color_v = has_eval_color::value; +#pragma endregion + +#pragma region has_eval_fanins_color +template +struct has_eval_fanins_color : std::false_type +{ +}; + +template +struct has_eval_fanins_color().eval_fanins_color( std::declval>(), std::declval() ) )>> : std::true_type +{ +}; + +template +inline constexpr bool has_eval_fanins_color_v = has_eval_fanins_color::value; +#pragma endregion + /*! \brief SFINAE based on iterator type (for compute functions). */ template diff --git a/include/mockturtle/views/color_view.hpp b/include/mockturtle/views/color_view.hpp index 86a9334b5..a93be7153 100644 --- a/include/mockturtle/views/color_view.hpp +++ b/include/mockturtle/views/color_view.hpp @@ -35,7 +35,6 @@ namespace mockturtle { - /*!\brief Manager view for traversal IDs (in-place storage). * * Traversal IDs, called colors, are unsigned integers that can be diff --git a/test/views/color_view.cpp b/test/views/color_view.cpp index be2fa105b..feb4e1abb 100644 --- a/test/views/color_view.cpp +++ b/test/views/color_view.cpp @@ -1,11 +1,57 @@ #include -#include #include +#include +#include +#include +#include +#include #include using namespace mockturtle; +template +void test_color_view() +{ + CHECK( is_network_type_v ); + CHECK( !has_new_color_v ); + CHECK( !has_current_color_v ); + CHECK( !has_clear_colors_v ); + CHECK( !has_color_v ); + CHECK( !has_paint_v ); + CHECK( !has_eval_color_v ); + CHECK( !has_eval_fanins_color_v ); + + using color_ntk = color_view; + CHECK( is_network_type_v ); + CHECK( has_new_color_v ); + CHECK( has_current_color_v ); + CHECK( has_clear_colors_v ); + CHECK( has_color_v ); + CHECK( has_paint_v ); + CHECK( has_eval_color_v ); + CHECK( has_eval_fanins_color_v ); + + using color_color_ntk = color_view; + CHECK( is_network_type_v ); + CHECK( has_new_color_v ); + CHECK( has_current_color_v ); + CHECK( has_clear_colors_v ); + CHECK( has_color_v ); + CHECK( has_paint_v ); + CHECK( has_eval_color_v ); + CHECK( has_eval_fanins_color_v ); +}; + +TEST_CASE( "create different color views", "[color_view]" ) +{ + test_color_view(); + test_color_view(); + test_color_view(); + test_color_view(); + test_color_view(); +} + TEST_CASE( "in-place color view", "[color_view]" ) { aig_network _aig; diff --git a/test/views/fanout_view.cpp b/test/views/fanout_view.cpp index 2b8b1e28b..6c40a9d60 100644 --- a/test/views/fanout_view.cpp +++ b/test/views/fanout_view.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -31,6 +33,8 @@ TEST_CASE( "create different fanout views", "[fanout_view]" ) { test_fanout_view(); test_fanout_view(); + test_fanout_view(); + test_fanout_view(); test_fanout_view(); } From d2166c4c4af84bb2b953d1ba484ae726234d7e5b Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 15 Oct 2020 15:06:46 +0200 Subject: [PATCH 25/30] window_utils. --- docs/implementations.rst | 14 + docs/views.rst | 11 + include/mockturtle/utils/window_utils.hpp | 153 ++++++++++ include/mockturtle/views/color_view.hpp | 3 +- test/utils/window_utils.cpp | 211 +++++++++++++ test/views/color_view.cpp | 10 + test/views/window_view.cpp | 353 ---------------------- 7 files changed, 401 insertions(+), 354 deletions(-) create mode 100644 test/utils/window_utils.cpp diff --git a/docs/implementations.rst b/docs/implementations.rst index 017dc1b5e..fe57a426e 100644 --- a/docs/implementations.rst +++ b/docs/implementations.rst @@ -284,3 +284,17 @@ All network implementations are located in `mockturtle/networks/`: +--------------------------------+-------------+-------------+-------------+-------------+-----------------+ | ``get_output_name`` | | | | | | +--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| | *Coloring methods* | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| ``new_color`` | | | | | | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| ``current_color`` | | | | | | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| ``color`` | | | | | | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| ``paint`` | | | | | | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| ``eval_color`` | | | | | | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ +| ``eval_fanins_color`` | | | | | | ++--------------------------------+-------------+-------------+-------------+-------------+-----------------+ diff --git a/docs/views.rst b/docs/views.rst index cedac7a73..a60cc6469 100644 --- a/docs/views.rst +++ b/docs/views.rst @@ -89,3 +89,14 @@ algorithm. Several views are implemented in mockturtle. .. doxygenclass:: mockturtle::cnf_view :members: + +`color_view`: Manages traversal IDs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Header:** ``mockturtle/views/color_view.hpp`` + +.. doxygenclass:: mockturtle::color_view + :members: + + .. doxygenclass:: mockturtle::out_of_place_color_view + :members: diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 04805b75f..53c0bb83e 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -708,4 +708,157 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector +class create_window_impl +{ +public: + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + struct window_info + { + std::vector inputs; + std::vector nodes; + std::vector outputs; + }; + +protected: + /* constant node used to denotes invalid window element */ + static constexpr node INVALID_NODE{0}; + +public: + create_window_impl( Ntk const& ntk ) + : ntk( ntk ) + , path( ntk.size() ) + , refs( ntk.size() ) + { + } + + std::optional run( node const& pivot ) + { + /* find a reconvergence from the pivot and collect the nodes */ + std::optional> nodes; + if ( !( nodes = identify_reconvergence( pivot, 1u ) ) ) + { + /* if there is no reconvergence, then optimization is not possible */ + return std::nullopt; + } + + /* collect the fanins for these nodes */ + ntk.new_color(); + std::vector inputs = collect_inputs( ntk, *nodes ); + + /* expand the nodes towards the TFI */ + ntk.new_color(); + expand_towards_tfi( ntk, inputs, 6u ); + + /* expand the nodes towards the TFO */ + ntk.new_color(); + levelized_expand_towards_tfo( ntk, inputs, *nodes ); + + /* collect the nodes with fanout outside of nodes */ + ntk.new_color(); + std::vector outputs = collect_outputs( ntk, inputs, *nodes, refs ); + + /* top. sort nodes */ + std::sort( std::begin( inputs ), std::end( inputs ) ); + std::sort( std::begin( *nodes ), std::end( *nodes ) ); + + return window_info{inputs, *nodes, outputs}; + } + +protected: + std::optional> identify_reconvergence( node const& pivot, uint64_t num_iterations ) + { + visited.clear(); + ntk.foreach_fanin( pivot, [&]( signal const& fi ){ + uint32_t const color = ntk.new_color(); + node const& n = ntk.get_node( fi ); + path[n] = INVALID_NODE; + visited.push_back( n ); + ntk.paint( n, color ); + }); + + uint64_t start{0}; + uint64_t stop; + for ( uint32_t iteration = 0u; iteration < num_iterations; ++iteration ) + { + stop = visited.size(); + for ( uint32_t i = start; i < stop; ++i ) + { + node const n = visited.at( i ); + std::optional meet = explore_frontier_of_node( n ); + if ( meet ) + { + visited.clear(); + gather_nodes_recursively( *meet ); + gather_nodes_recursively( n ); + visited.push_back( pivot ); + return visited; + } + } + start = stop; + } + + return std::nullopt; + } + + std::optional explore_frontier_of_node( node const& n ) + { + std::optional meet; + ntk.foreach_fanin( n, [&]( signal const& fi ){ + node const& fi_node = ntk.get_node( fi ); + if ( ntk.is_constant( fi_node ) || ntk.is_ci( fi_node ) ) + { + return true; /* next */ + } + + if ( ntk.eval_color( n, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } )&& + ntk.eval_color( fi_node, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } ) && + ntk.eval_color( n, fi_node, []( auto c0, auto c1 ){ return c0 != c1; } ) ) + { + meet = fi_node; + return false; + } + + if ( ntk.eval_color( fi_node, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } ) ) + { + return true; /* next */ + } + + ntk.paint( fi_node, n ); + path[fi_node] = n; + visited.push_back( fi_node ); + return true; /* next */ + }); + + return meet; + } + + /* collect nodes recursively following along the `path` until INVALID_NODE is reached */ + void gather_nodes_recursively( node const& n ) + { + if ( n == INVALID_NODE ) + { + return; + } + + visited.push_back( n ); + node const pred = path[n]; + if ( pred == INVALID_NODE ) + { + return; + } + + assert( ntk.eval_color( n, pred, []( auto c0, auto c1 ){ return c0 == c1; } ) ); + gather_nodes_recursively( pred ); + } + +protected: + Ntk const& ntk; + std::vector visited; + std::vector path; + std::vector refs; +}; /* create_window_impl */ + } /* namespace mockturtle */ diff --git a/include/mockturtle/views/color_view.hpp b/include/mockturtle/views/color_view.hpp index a93be7153..c9a229209 100644 --- a/include/mockturtle/views/color_view.hpp +++ b/include/mockturtle/views/color_view.hpp @@ -25,7 +25,7 @@ /*! \file color_view.hpp - \brief Color view + \brief Manager view for traversal IDs, called colors \author Heinz Riener */ @@ -185,6 +185,7 @@ class out_of_place_color_view : public Ntk return values[n]; } + template>> auto color( signal const& n ) const { return values[this->get_node( n )]; diff --git a/test/utils/window_utils.cpp b/test/utils/window_utils.cpp new file mode 100644 index 000000000..1792a03d5 --- /dev/null +++ b/test/utils/window_utils.cpp @@ -0,0 +1,211 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace mockturtle; + +TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) +{ + using node = typename aig_network::node; + + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); + + color_view aig{_aig}; + { + aig.new_color(); + + /* a cut that can be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); + CHECK( trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + } + + { + aig.new_color(); + + /* a cut that cannot be expanded without increasing cut-size */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); + } + + { + aig.new_color(); + + /* a cut that can be moved towards the PIs */ + std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); + } + + { + aig.new_color(); + + /* the cut { f3, f5 } can be simplified to { f3, f4 } */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); + } + + { + aig.new_color(); + + /* the cut { f4, f5 } also can be simplified to { f3, f4 } */ + std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; + + bool const trivial_cut = expand0_towards_tfi( aig, inputs ); + CHECK( !trivial_cut ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); + } +} + +TEST_CASE( "expand node set towards TFI", "[window_utils]" ) +{ + using node = typename aig_network::node; + + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); + + color_view aig{_aig}; + + { + /* expand from { f5 } to 4-cut { a, b, c, d } */ + std::vector inputs{aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 4u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); + } + + { + /* expand from { f3, f5 } to 3-cut { a, b, f2 } */ + std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 3u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); + } + + { + /* expand from { f4, f5 } to 3-cut { a, b, f2 } */ + std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; + expand_towards_tfi( aig, inputs, 3u ); + + std::sort( std::begin( inputs ), std::end( inputs ) ); + CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); + } +} + +TEST_CASE( "expand node set towards TFO", "[window_utils]" ) +{ + using node = typename aig_network::node; + + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); + + std::vector inputs{_aig.get_node( a ), _aig.get_node( b ), _aig.get_node( c ), _aig.get_node( d )}; + + fanout_view fanout_aig{_aig}; + depth_view depth_aig{fanout_aig}; + color_view aig{depth_aig}; + + { + std::vector nodes; + expand_towards_tfo( aig, inputs, nodes ); + + std::sort( std::begin( nodes ), std::end( nodes ) ); + CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), + aig.get_node( f4 ), aig.get_node( f5 )} ); + } + + { + std::vector nodes; + levelized_expand_towards_tfo( aig, inputs, nodes ); + + std::sort( std::begin( nodes ), std::end( nodes ) ); + CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f4 )} ); + } +} + +TEST_CASE( "create window from pivot", "[window_utils]" ) +{ + aig_network _aig; + auto const a = _aig.create_pi(); + auto const b = _aig.create_pi(); + auto const c = _aig.create_pi(); + auto const d = _aig.create_pi(); + auto const f1 = _aig.create_and( b, c ); + auto const f2 = _aig.create_and( b, f1 ); + auto const f3 = _aig.create_and( a, f2 ); + auto const f4 = _aig.create_and( d, f2 ); + auto const f5 = _aig.create_and( f3, f4 ); + _aig.create_po( f5 ); + + fanout_view fanout_aig{_aig}; + depth_view depth_aig{fanout_aig}; + color_view aig{depth_aig}; + aig.new_color(); + + create_window_impl windowing( aig ); + auto info = windowing.run( aig.get_node( f5 ) ); + CHECK( info ); + if ( info ) + { + window_view win( aig, info->inputs, info->outputs, info->nodes ); + CHECK( win.num_cis() == 4u ); + CHECK( win.num_cos() == 2u ); + CHECK( win.num_gates() == 4u ); + } +} diff --git a/test/views/color_view.cpp b/test/views/color_view.cpp index feb4e1abb..647b9d4e9 100644 --- a/test/views/color_view.cpp +++ b/test/views/color_view.cpp @@ -41,6 +41,16 @@ void test_color_view() CHECK( has_paint_v ); CHECK( has_eval_color_v ); CHECK( has_eval_fanins_color_v ); + + using out_of_place_color_ntk = out_of_place_color_view; + CHECK( is_network_type_v ); + CHECK( has_new_color_v ); + CHECK( has_current_color_v ); + CHECK( has_clear_colors_v ); + CHECK( has_color_v ); + CHECK( has_paint_v ); + CHECK( has_eval_color_v ); + CHECK( has_eval_fanins_color_v ); }; TEST_CASE( "create different color views", "[color_view]" ) diff --git a/test/views/window_view.cpp b/test/views/window_view.cpp index 1c148bd7d..35275c65a 100644 --- a/test/views/window_view.cpp +++ b/test/views/window_view.cpp @@ -256,356 +256,3 @@ TEST_CASE( "expand towards tfo", "[window_view]" ) CHECK( std::find( std::begin( gates ), std::end( gates ), n ) != std::end( gates ) ); }); } - -template -class create_window_impl -{ -public: - using node = typename Ntk::node; - using signal = typename Ntk::signal; - - struct window_info - { - std::vector inputs; - std::vector nodes; - std::vector outputs; - }; - -protected: - /* constant node used to denotes invalid window element */ - static constexpr node INVALID_NODE{0}; - -public: - create_window_impl( Ntk const& ntk ) - : ntk( ntk ) - , path( ntk.size() ) - , refs( ntk.size() ) - { - } - - std::optional run( node const& pivot ) - { - /* find a reconvergence from the pivot and collect the nodes */ - std::optional> nodes; - if ( !( nodes = identify_reconvergence( pivot, 1u ) ) ) - { - /* if there is no reconvergence, then optimization is not possible */ - return std::nullopt; - } - - /* collect the fanins for these nodes */ - ntk.new_color(); - std::vector inputs = collect_inputs( ntk, *nodes ); - - /* expand the nodes towards the TFI */ - ntk.new_color(); - expand_towards_tfi( ntk, inputs, 6u ); - - /* expand the nodes towards the TFO */ - ntk.new_color(); - levelized_expand_towards_tfo( ntk, inputs, *nodes ); - - /* collect the nodes with fanout outside of nodes */ - ntk.new_color(); - std::vector outputs = collect_outputs( ntk, inputs, *nodes, refs ); - - /* top. sort nodes */ - std::sort( std::begin( inputs ), std::end( inputs ) ); - std::sort( std::begin( *nodes ), std::end( *nodes ) ); - - return window_info{inputs, *nodes, outputs}; - } - -protected: - std::optional> identify_reconvergence( node const& pivot, uint64_t num_iterations ) - { - visited.clear(); - ntk.foreach_fanin( pivot, [&]( signal const& fi ){ - uint32_t const color = ntk.new_color(); - node const& n = ntk.get_node( fi ); - path[n] = INVALID_NODE; - visited.push_back( n ); - ntk.paint( n, color ); - }); - - uint64_t start{0}; - uint64_t stop; - for ( uint32_t iteration = 0u; iteration < num_iterations; ++iteration ) - { - stop = visited.size(); - for ( uint32_t i = start; i < stop; ++i ) - { - node const n = visited.at( i ); - std::optional meet = explore_frontier_of_node( n ); - if ( meet ) - { - visited.clear(); - gather_nodes_recursively( *meet ); - gather_nodes_recursively( n ); - visited.push_back( pivot ); - return visited; - } - } - start = stop; - } - - return std::nullopt; - } - - std::optional explore_frontier_of_node( node const& n ) - { - std::optional meet; - ntk.foreach_fanin( n, [&]( signal const& fi ){ - node const& fi_node = ntk.get_node( fi ); - if ( ntk.is_constant( fi_node ) || ntk.is_ci( fi_node ) ) - { - return true; /* next */ - } - - if ( ntk.eval_color( n, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } )&& - ntk.eval_color( fi_node, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } ) && - ntk.eval_color( n, fi_node, []( auto c0, auto c1 ){ return c0 != c1; } ) ) - { - meet = fi_node; - return false; - } - - if ( ntk.eval_color( fi_node, [this]( auto c ){ return c > ntk.current_color() - ntk.max_fanin_size; } ) ) - { - return true; /* next */ - } - - ntk.paint( fi_node, n ); - path[fi_node] = n; - visited.push_back( fi_node ); - return true; /* next */ - }); - - return meet; - } - - /* collect nodes recursively following along the `path` until INVALID_NODE is reached */ - void gather_nodes_recursively( node const& n ) - { - if ( n == INVALID_NODE ) - { - return; - } - - visited.push_back( n ); - node const pred = path[n]; - if ( pred == INVALID_NODE ) - { - return; - } - - assert( ntk.eval_color( n, pred, []( auto c0, auto c1 ){ return c0 == c1; } ) ); - gather_nodes_recursively( pred ); - } - -protected: - Ntk const& ntk; - std::vector visited; - std::vector path; - std::vector refs; -}; /* create_window_impl */ - -TEST_CASE( "expand node set towards TFI without cut-size", "[window_utils]" ) -{ - using node = typename aig_network::node; - - aig_network _aig; - auto const a = _aig.create_pi(); - auto const b = _aig.create_pi(); - auto const c = _aig.create_pi(); - auto const d = _aig.create_pi(); - auto const f1 = _aig.create_and( b, c ); - auto const f2 = _aig.create_and( b, f1 ); - auto const f3 = _aig.create_and( a, f2 ); - auto const f4 = _aig.create_and( d, f2 ); - auto const f5 = _aig.create_and( f3, f4 ); - _aig.create_po( f5 ); - - color_view aig{_aig}; - { - aig.new_color(); - - /* a cut that can be expanded without increasing cut-size */ - std::vector inputs{aig.get_node( a ), aig.get_node( b ), aig.get_node( f1 ), aig.get_node( d )}; - - bool const trivial_cut = expand0_towards_tfi( aig, inputs ); - CHECK( trivial_cut ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); - } - - { - aig.new_color(); - - /* a cut that cannot be expanded without increasing cut-size */ - std::vector inputs{aig.get_node( f3 ), aig.get_node( f4 )}; - - bool const trivial_cut = expand0_towards_tfi( aig, inputs ); - CHECK( !trivial_cut ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); - } - - { - aig.new_color(); - - /* a cut that can be moved towards the PIs */ - std::vector inputs{aig.get_node( f2 ), aig.get_node( f3 ), aig.get_node( f4 )}; - - bool const trivial_cut = expand0_towards_tfi( aig, inputs ); - CHECK( !trivial_cut ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); - } - - { - aig.new_color(); - - /* the cut { f3, f5 } can be simplified to { f3, f4 } */ - std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - - bool const trivial_cut = expand0_towards_tfi( aig, inputs ); - CHECK( !trivial_cut ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); - } - - { - aig.new_color(); - - /* the cut { f4, f5 } also can be simplified to { f3, f4 } */ - std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; - - bool const trivial_cut = expand0_towards_tfi( aig, inputs ); - CHECK( !trivial_cut ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( f3 ), aig.get_node( f4 )} ); - } -} - -TEST_CASE( "expand node set towards TFI", "[window_utils]" ) -{ - using node = typename aig_network::node; - - aig_network _aig; - auto const a = _aig.create_pi(); - auto const b = _aig.create_pi(); - auto const c = _aig.create_pi(); - auto const d = _aig.create_pi(); - auto const f1 = _aig.create_and( b, c ); - auto const f2 = _aig.create_and( b, f1 ); - auto const f3 = _aig.create_and( a, f2 ); - auto const f4 = _aig.create_and( d, f2 ); - auto const f5 = _aig.create_and( f3, f4 ); - _aig.create_po( f5 ); - - color_view aig{_aig}; - - { - /* expand from { f5 } to 4-cut { a, b, c, d } */ - std::vector inputs{aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 4u ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( b ), aig.get_node( c ), aig.get_node( d )} ); - } - - { - /* expand from { f3, f5 } to 3-cut { a, b, f2 } */ - std::vector inputs{aig.get_node( f3 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); - } - - { - /* expand from { f4, f5 } to 3-cut { a, b, f2 } */ - std::vector inputs{aig.get_node( f4 ), aig.get_node( f5 )}; - expand_towards_tfi( aig, inputs, 3u ); - - std::sort( std::begin( inputs ), std::end( inputs ) ); - CHECK( inputs == std::vector{aig.get_node( a ), aig.get_node( d ), aig.get_node( f2 )} ); - } -} - -TEST_CASE( "expand node set towards TFO", "[window_utils]" ) -{ - using node = typename aig_network::node; - - aig_network _aig; - auto const a = _aig.create_pi(); - auto const b = _aig.create_pi(); - auto const c = _aig.create_pi(); - auto const d = _aig.create_pi(); - auto const f1 = _aig.create_and( b, c ); - auto const f2 = _aig.create_and( b, f1 ); - auto const f3 = _aig.create_and( a, f2 ); - auto const f4 = _aig.create_and( d, f2 ); - auto const f5 = _aig.create_and( f3, f4 ); - _aig.create_po( f5 ); - - std::vector inputs{_aig.get_node( a ), _aig.get_node( b ), _aig.get_node( c ), _aig.get_node( d )}; - - fanout_view fanout_aig{_aig}; - depth_view depth_aig{fanout_aig}; - color_view aig{depth_aig}; - - { - std::vector nodes; - expand_towards_tfo( aig, inputs, nodes ); - - std::sort( std::begin( nodes ), std::end( nodes ) ); - CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), - aig.get_node( f4 ), aig.get_node( f5 )} ); - } - - { - std::vector nodes; - levelized_expand_towards_tfo( aig, inputs, nodes ); - - std::sort( std::begin( nodes ), std::end( nodes ) ); - CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f4 )} ); - } -} - -TEST_CASE( "make a window", "[create_window]" ) -{ - aig_network _aig; - auto const a = _aig.create_pi(); - auto const b = _aig.create_pi(); - auto const c = _aig.create_pi(); - auto const d = _aig.create_pi(); - auto const f1 = _aig.create_and( b, c ); - auto const f2 = _aig.create_and( b, f1 ); - auto const f3 = _aig.create_and( a, f2 ); - auto const f4 = _aig.create_and( d, f2 ); - auto const f5 = _aig.create_and( f3, f4 ); - _aig.create_po( f5 ); - - fanout_view fanout_aig{_aig}; - depth_view depth_aig{fanout_aig}; - color_view aig{depth_aig}; - aig.new_color(); - - create_window_impl windowing( aig ); - auto info = windowing.run( aig.get_node( f5 ) ); - CHECK( info ); - if ( info ) - { - window_view win( aig, info->inputs, info->outputs, info->nodes ); - CHECK( win.num_cis() == 4u ); - CHECK( win.num_cos() == 2u ); - CHECK( win.num_gates() == 4u ); - } -} From 74ff92b994d0ae9cae196c71af6c18ec5c358389 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Thu, 15 Oct 2020 16:03:11 +0200 Subject: [PATCH 26/30] window_utils. --- include/mockturtle/utils/window_utils.hpp | 62 ++++++++++++++--------- test/utils/window_utils.cpp | 16 +++--- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 53c0bb83e..94d87bb62 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -30,6 +30,8 @@ \author Heinz Riener */ +#pragma once + #include #include #include @@ -213,13 +215,9 @@ std::vector collect_inputs( Ntk const& ntk, std::vector inline std::vector collect_outputs( Ntk const& ntk, @@ -503,13 +501,7 @@ void expand_towards_tfi( Ntk const& ntk, std::vector& inputs * - `foreach_fanin` * - `foreach_fanout` * - `get_node` - * - `incr_trav_id` * - `is_ci` - * - `set_visited` - * - `trav_id` - * - `visited` - * - `eval_color` - * - `current_color` * - `new_color` */ template @@ -590,7 +582,7 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& assert( ep != 0 ); assert( !ntk.is_ci( ep ) ); nodes.emplace_back( ep ); - ntk.set_visited( ep, ntk.trav_id() ); + ntk.paint( ep ); it = eps.erase( it ); explore_fanouts( ntk, ep, new_eps ); @@ -624,18 +616,18 @@ void expand_towards_tfo( Ntk const& ntk, std::vector const& * \param nodes Inner nodes of a window * * **Required network functions:** + * - `current_color` + * - `depth` + * - `eval_color` + * - `eval_fanins_color` * - `foreach_fanin` * - `foreach_fanout` * - `get_node` - * - `level` - * - `is_constant` * - `is_ci` - * - `depth` - * - `paint` - * - `eval_color` - * - `current_color` - * - `eval_fanins_color` + * - `is_constant` + * - `level` * - `new_color` + * - `paint` */ template void levelized_expand_towards_tfo( Ntk const& ntk, std::vector const& inputs, std::vector& nodes ) @@ -708,6 +700,27 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector class create_window_impl { @@ -715,7 +728,7 @@ class create_window_impl using node = typename Ntk::node; using signal = typename Ntk::signal; - struct window_info + struct window { std::vector inputs; std::vector nodes; @@ -726,6 +739,9 @@ class create_window_impl /* constant node used to denotes invalid window element */ static constexpr node INVALID_NODE{0}; + /* number of iterations */ + static constexpr uint32_t NUM_ITERATIONS{5}; + public: create_window_impl( Ntk const& ntk ) : ntk( ntk ) @@ -734,11 +750,11 @@ class create_window_impl { } - std::optional run( node const& pivot ) + std::optional run( node const& pivot, uint32_t cut_size ) { /* find a reconvergence from the pivot and collect the nodes */ std::optional> nodes; - if ( !( nodes = identify_reconvergence( pivot, 1u ) ) ) + if ( !( nodes = identify_reconvergence( pivot, NUM_ITERATIONS ) ) ) { /* if there is no reconvergence, then optimization is not possible */ return std::nullopt; @@ -750,7 +766,7 @@ class create_window_impl /* expand the nodes towards the TFI */ ntk.new_color(); - expand_towards_tfi( ntk, inputs, 6u ); + expand_towards_tfi( ntk, inputs, cut_size ); /* expand the nodes towards the TFO */ ntk.new_color(); @@ -764,7 +780,7 @@ class create_window_impl std::sort( std::begin( inputs ), std::end( inputs ) ); std::sort( std::begin( *nodes ), std::end( *nodes ) ); - return window_info{inputs, *nodes, outputs}; + return window{inputs, *nodes, outputs}; } protected: diff --git a/test/utils/window_utils.cpp b/test/utils/window_utils.cpp index 1792a03d5..43572763a 100644 --- a/test/utils/window_utils.cpp +++ b/test/utils/window_utils.cpp @@ -1,12 +1,12 @@ #include #include -#include +#include +#include #include #include -#include -#include -#include +#include +#include using namespace mockturtle; @@ -179,7 +179,7 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) } } -TEST_CASE( "create window from pivot", "[window_utils]" ) +TEST_CASE( "create window for pivot", "[window_utils]" ) { aig_network _aig; auto const a = _aig.create_pi(); @@ -199,11 +199,9 @@ TEST_CASE( "create window from pivot", "[window_utils]" ) aig.new_color(); create_window_impl windowing( aig ); - auto info = windowing.run( aig.get_node( f5 ) ); - CHECK( info ); - if ( info ) + if ( auto w = windowing.run( aig.get_node( f5 ), 6u ) ) { - window_view win( aig, info->inputs, info->outputs, info->nodes ); + window_view win( aig, w->inputs, w->outputs, w->nodes ); CHECK( win.num_cis() == 4u ); CHECK( win.num_cos() == 2u ); CHECK( win.num_gates() == 4u ); From b4a5c7f9d32428fefc9b2a618f5d87fda3e9d6cc Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Fri, 16 Oct 2020 16:43:02 +0200 Subject: [PATCH 27/30] quality test. --- include/mockturtle/utils/window_utils.hpp | 51 +++++++++++++++-------- test/algorithms/quality.cpp | 42 +++++++++++++++++++ test/utils/window_utils.cpp | 1 - 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/include/mockturtle/utils/window_utils.hpp b/include/mockturtle/utils/window_utils.hpp index 94d87bb62..d19027440 100644 --- a/include/mockturtle/utils/window_utils.hpp +++ b/include/mockturtle/utils/window_utils.hpp @@ -165,9 +165,8 @@ std::vector collect_inputs( Ntk const& ntk, std::vector collect_inputs( Ntk const& ntk, std::vector collect_outputs( Ntk const& ntk, std::vector outputs; /* mark the inputs visited */ + ntk.new_color(); for ( auto const& i : inputs ) { ntk.paint( i ); @@ -250,7 +251,7 @@ inline std::vector collect_outputs( Ntk const& ntk, } /* if the fanout_size of a node does not match the reference count, - the node has fanout outside of the window is an output */ + the node has fanouts outside of the window is an output */ for ( const auto& n : nodes ) { if ( ntk.eval_color( n, [&ntk]( auto c ){ return c == ntk.current_color(); } ) ) @@ -410,8 +411,14 @@ inline typename Ntk::node select_next_fanin_to_expand_tfi( Ntk const& ntk, std:: { continue; } + ntk.foreach_fanin( i, [&]( signal const& fi ){ + if ( ntk.is_constant( ntk.get_node( fi ) ) ) + { + return true; + } detail::evaluate_fanin( ntk.get_node( fi ), candidates ); + return true; }); } @@ -639,9 +646,10 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector> levels( ntk.depth() ); + std::vector> levels; + levels.resize( ntk.depth() + 1 ); - /* list of indicves of used levels (avoid iterating over all levels) */ + /* list of indices of used levels (avoid iterating over all levels) */ std::vector used; /* remove all nodes */ @@ -652,19 +660,20 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector& level = levels.at( index ); - for ( auto it = std::begin( level ); it != std::end( level ); ++it ) + for ( auto j = 0u; j < level.size(); ++j ) { - ntk.foreach_fanout( *it, [&]( node const& fo, uint64_t index ){ + ntk.foreach_fanout( level[j], [&]( node const& fo, uint64_t index ){ /* avoid getting stuck on nodes with many fanouts */ if ( index == MAX_FANOUTS ) { @@ -761,20 +770,26 @@ class create_window_impl } /* collect the fanins for these nodes */ - ntk.new_color(); std::vector inputs = collect_inputs( ntk, *nodes ); + if ( inputs.size() > cut_size ) + { + return std::nullopt; + } /* expand the nodes towards the TFI */ - ntk.new_color(); expand_towards_tfi( ntk, inputs, cut_size ); + assert( inputs.size() <= cut_size ); /* expand the nodes towards the TFO */ - ntk.new_color(); levelized_expand_towards_tfo( ntk, inputs, *nodes ); + if ( nodes->empty() ) + { + return std::nullopt; + } /* collect the nodes with fanout outside of nodes */ - ntk.new_color(); std::vector outputs = collect_outputs( ntk, inputs, *nodes, refs ); + assert( outputs.size() > 0u ); /* top. sort nodes */ std::sort( std::begin( inputs ), std::end( inputs ) ); @@ -786,6 +801,8 @@ class create_window_impl protected: std::optional> identify_reconvergence( node const& pivot, uint64_t num_iterations ) { + ntk.new_color(); + visited.clear(); ntk.foreach_fanin( pivot, [&]( signal const& fi ){ uint32_t const color = ntk.new_color(); diff --git a/test/algorithms/quality.cpp b/test/algorithms/quality.cpp index c2a0102e2..95ffb12f3 100644 --- a/test/algorithms/quality.cpp +++ b/test/algorithms/quality.cpp @@ -338,4 +338,46 @@ TEST_CASE( "Test quality improvement for XMG3 Resubstitution", "[quality]" ) CHECK( v == std::vector{{0, 38, 46, 22, 62, 72, 76, 75, 273, 865, 190}} ); } +TEST_CASE( "Test quality of 6-input windowing for AIG", "[quality]" ) +{ + std::vector> const result = + {{1, 4, 2, 4}, + {64, 384, 178, 312}, + {40, 240, 64, 296}, + {44, 264, 81, 173}, + {152, 784, 232, 616}, + {71, 401, 149, 337}, + {106, 636, 190, 500}, + {242, 1440, 1075, 1321}, + {215, 1232, 903, 1683}, + {1161, 6871, 2366, 2904}, + {388, 2229, 2151, 3179}}; + + const auto v = foreach_benchmark( [&]( auto& ntk, auto ){ + fanout_view fntk{ntk}; + depth_view dntk{fntk}; + color_view aig{dntk}; + + uint32_t num_windows{0}; + uint32_t num_pis{0}; + uint32_t num_pos{0}; + uint32_t num_gates{0}; + + create_window_impl windowing( aig ); + aig.foreach_node( [&]( aig_network::node const& n ){ + if ( const auto w = windowing.run( n, 6u ) ) + { + window_view win( aig, w->inputs, w->outputs, w->nodes ); + ++num_windows; + num_pis += win.num_pis(); + num_pos += win.num_pos(); + num_gates += win.num_gates(); + } + }); + return std::make_tuple( num_windows, num_pis, num_pos, num_gates ); + }); + + CHECK( v == result ); +} + #endif diff --git a/test/utils/window_utils.cpp b/test/utils/window_utils.cpp index 43572763a..007642793 100644 --- a/test/utils/window_utils.cpp +++ b/test/utils/window_utils.cpp @@ -196,7 +196,6 @@ TEST_CASE( "create window for pivot", "[window_utils]" ) fanout_view fanout_aig{_aig}; depth_view depth_aig{fanout_aig}; color_view aig{depth_aig}; - aig.new_color(); create_window_impl windowing( aig ); if ( auto w = windowing.run( aig.get_node( f5 ), 6u ) ) From 72a1d4369682255bedd9840719f3441038837c6d Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Fri, 16 Oct 2020 16:59:42 +0200 Subject: [PATCH 28/30] update tests. --- test/utils/window_utils.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/utils/window_utils.cpp b/test/utils/window_utils.cpp index 007642793..21130d25c 100644 --- a/test/utils/window_utils.cpp +++ b/test/utils/window_utils.cpp @@ -175,7 +175,8 @@ TEST_CASE( "expand node set towards TFO", "[window_utils]" ) levelized_expand_towards_tfo( aig, inputs, nodes ); std::sort( std::begin( nodes ), std::end( nodes ) ); - CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f4 )} ); + CHECK( nodes == std::vector{aig.get_node( f1 ), aig.get_node( f2 ), aig.get_node( f3 ), + aig.get_node( f4 ), aig.get_node( f5 )} ); } } @@ -202,7 +203,7 @@ TEST_CASE( "create window for pivot", "[window_utils]" ) { window_view win( aig, w->inputs, w->outputs, w->nodes ); CHECK( win.num_cis() == 4u ); - CHECK( win.num_cos() == 2u ); - CHECK( win.num_gates() == 4u ); + CHECK( win.num_cos() == 1u ); + CHECK( win.num_gates() == 5u ); } } From 3ee7a0f7db7105e539d0f7adbe8c9faed08a5e8c Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 19 Oct 2020 10:25:33 +0200 Subject: [PATCH 29/30] interface. --- include/mockturtle/interface.hpp | 64 +++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/include/mockturtle/interface.hpp b/include/mockturtle/interface.hpp index 6d97e4da2..54df39655 100644 --- a/include/mockturtle/interface.hpp +++ b/include/mockturtle/interface.hpp @@ -916,17 +916,69 @@ class network final /*! \brief Sets the visited value of a node. */ void set_visited( node const& n, uint32_t v ) const; - /*! \brief An id that can be used as a visited flag. - * - * By using the traversal is, one can reuse multiple visited flags over - * several levels. - */ + /*! \brief Returns the current traversal id. */ uint32_t trav_id() const; /*! \brief Increment the current traversal id. */ void incr_trav_id() const; #pragma endregion +#pragma beginregion Color values + /* Color values offer a more recent and flexible mechanism to manage + and manipulate traversal ids. */ + + /*! \brief Returns a new color and increases the current color. */ + uint32_t new_color() const; + + /*! \brief Returns the current color. */ + uint32_t current_color() const; + + /*! \brief Resets all nodes colors to value `color`. */ + void clear_colors( uint32_t color = 0 ) const; + + /*! \brief Returns the color of a node. */ + auto color( node const& n ) const; + + /*! \brief Returns the color of a node. */ + auto color( signal const& n ) const; + + /*! \brief Assigns the current color to a node. */ + void paint( node const& n ) const; + + /*! \brief Assigns `color` to a node. */ + void paint( node const& n, uint32_t color ) const; + + /*! \brief Copies the color from `other` to `n`. */ + void paint( node const& n, node const& other ) const; + + /*! \brief Evaluates a predicate on the color of a node. + * + * The predicate `pred` is any callable that must have the signature + * ``bool(color_type)``, where `color_type` is the + * implementation-dependent type returned by the method `color`. + */ + template + bool eval_color( node const& n, Pred&& pred ) const; + + /*! \brief Evaluates a predicate on the colors of two nodes. + * + * The predicate `pred` is any callable that must have the signature + * ``bool(color_type,color_type)``, where `color_type` is the + * implementation-dependent type returned by the method `color`. + */ + template + bool eval_color( node const& a, node const& b, Pred&& pred ) const; + + /*! \brief Evaluates a predicate on the colors of the fanins of a node. + * + * The predicate `pred` is any callable that must have the signature + * ``bool(color_type)``, where `color_type` is the + * implementation-dependent type returned by the method `color`. + */ + template + bool eval_fanins_color( node const& n, Pred&& pred ) const; +#pragma endregion + #pragma region Signal naming /*! \brief Checks if a signal has a name. */ bool has_name( signal const& s ) const; @@ -945,7 +997,7 @@ class network final /*! \brief Returns the name of an output signal. */ std::string get_output_name( uint32_t index ) const; -#end endregion +#pragma endregion #pragma region General methods /*! \brief Returns network events object. From 28020ca2d0b6000520b0abe1dc1175679a27bfea Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 19 Oct 2020 10:55:10 +0200 Subject: [PATCH 30/30] changelog. --- docs/changelog.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index ce67dd471..15beb1ca4 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -35,6 +35,8 @@ v0.2 (not yet released) * Views: - Assign names to signals and outputs (`names_view`) `#181 `_ `#184 `_ - Creates a CNF while creating a network (`cnf_view`) `#274 `_ + - Revised window view (`window_view`) `#381 `_ + - In-place and out-of-place color view (`color_view`, `out_of_place_color_view`) `#381 `_ * I/O: - Write networks to DIMACS files for CNF (`write_dimacs`) `#146 `_ - Read BLIF files using *lorina* (`blif_reader`) `#167 `_ @@ -63,6 +65,8 @@ v0.2 (not yet released) - Random logic networks for XAGs (`random_logic_generator`) `#366 `_ * Properties: - Costs based on multiplicative complexity (`multiplicative_complexity` and `multiplicative_complexity_depth`) `#170 `_ +* Utils: + - Computing windows and manipulating cuts (`create_window_impl`, `collect_nodes`, `collect_inputs`, `collect_outputs`, `expand0_towards_tfi`, `expand_towards_tfi`, `expand_towards_tfo`, `levelized_expand_towards_tfo`) `#381 `_ v0.1 (March 31, 2019) ---------------------