From f18e1f339b6df7ff158b4065aa2f29338f63ee82 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 12 Oct 2020 15:41:11 +0200 Subject: [PATCH 01/14] mig_index_list. --- include/mockturtle/utils/index_list.hpp | 199 ++++++++++++++++++++++++ test/utils/index_list.cpp | 45 ++++++ 2 files changed, 244 insertions(+) create mode 100644 include/mockturtle/utils/index_list.hpp create mode 100644 test/utils/index_list.cpp diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp new file mode 100644 index 000000000..206d50118 --- /dev/null +++ b/include/mockturtle/utils/index_list.hpp @@ -0,0 +1,199 @@ +/* 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 index_list.hpp + \brief List of indices to represent small networks. + \author Heinz Riener +*/ + +#include +#include +#include + +namespace mockturtle +{ + +/*! \brief Index list for majority-inverter graphs. + * + * Small network consisting of majority gates and inverters + * represented as a list of indices. + */ +struct mig_index_list +{ +public: + using element_type = uint64_t; + +public: + explicit mig_index_list() + : values( 2u, 0u ) + {} + + explicit mig_index_list( std::vector const& values ) + : values( std::begin( values ), std::end( values ) ) + {} + + std::vector raw() const + { + return values; + } + + uint64_t size() const + { + return values.size(); + } + + uint64_t num_entries() const + { + return ( values.size() - 2u - num_pos() ) / 3u; + } + + uint64_t num_pis() const + { + return values.at( 0u ); + } + + uint64_t num_pos() const + { + return values.at( 1u ); + } + + template + void foreach_entry( Fn&& fn ) const + { + assert( ( values.size() - 2u - num_pos() ) % 3 == 0 ); + for ( uint64_t i = 2u; i < values.size() - num_pos(); i += 3 ) + { + fn( values.at( i ), values.at( i+1 ), values.at( i+2 ) ); + } + } + + template + void foreach_po( Fn&& fn ) const + { + for ( uint64_t i = values.size() - num_pos(); i < values.size(); ++i ) + { + fn( values.at( i ) ); + } + } + + void add_input() + { + ++values.at( 0u ); + } + + void add_gate( element_type lit0, element_type lit1, element_type lit2 ) + { + values.push_back( lit0 ); + values.push_back( lit1 ); + values.push_back( lit2 ); + } + + void add_output( element_type lit ) + { + ++values.at( 1u ); + values.push_back( lit ); + } + +private: + std::vector values; +}; + +/*! \brief Generates a network from an index_list */ +template +void encode( mig_index_list& indices, Ntk const& ntk ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + /* inputs */ + for ( uint64_t i = 0; i < ntk.num_pis(); ++i ) + { + indices.add_input(); + } + + /* gates */ + ntk.foreach_gate( [&]( node const& n ){ + std::array lits; + ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); + }); + indices.add_gate( lits[0u], lits[1u], lits[2u] ); + }); + + /* outputs */ + ntk.foreach_po( [&]( signal const& f ){ + indices.add_output( 2*ntk.node_to_index( ntk.get_node( f ) ) + ntk.is_complemented( f ) ); + }); + + assert( indices.size() == 2u + 3u*ntk.num_gates() + ntk.num_pos() ); +} + +/*! \brief Generates a network from an mig_index_list */ +template +void decode( Ntk& ntk, mig_index_list const& indices ) +{ + using signal = typename Ntk::signal; + + std::vector signals; + for ( uint64_t i = 0; i < indices.num_pis(); ++i ) + { + signals.push_back( ntk.create_pi() ); + } + + insert( ntk, std::begin( signals ), std::end( signals ), indices, + [&]( signal const& s ){ ntk.create_po( s ); }); +} + +/*! \brief Inserts a mig_index_list into an existing network */ +template +void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indices, Fn&& fn ) +{ + using signal = typename Ntk::signal; + + std::vector signals; + signals.emplace_back( ntk.get_constant( false ) ); + for ( auto it = begin; it != end; ++it ) + { + signals.push_back( *it ); + } + + indices.foreach_entry( [&]( uint64_t lit0, uint64_t lit1, uint64_t lit2 ){ + uint64_t const i0 = lit0 >> 1; + uint64_t const i1 = lit1 >> 1; + uint64_t const i2 = lit2 >> 1; + signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); + signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); + signal const s2 = ( lit2 % 2 ) ? !signals.at( i2 ) : signals.at( i2 ); + signals.push_back( ntk.create_maj( s0, s1, s2 ) ); + }); + + indices.foreach_po( [&]( uint64_t lit ){ + uint64_t const i = lit >> 1; + fn( ( lit % 2 ) ? !signals.at( i ) : signals.at( i ) ); + }); +} + +} /* mockturtle */ diff --git a/test/utils/index_list.cpp b/test/utils/index_list.cpp new file mode 100644 index 000000000..bafbec50f --- /dev/null +++ b/test/utils/index_list.cpp @@ -0,0 +1,45 @@ +#include + +#include +#include +#include +#include + +using namespace mockturtle; + +TEST_CASE( "decode mig_index_list into mig_network", "[index_list]" ) +{ + std::vector const raw_list{4, 1, 2, 4, 6, 10, 4, 8, 12}; + mig_index_list mig_il{raw_list}; + + mig_network mig; + decode( mig, mig_il ); + + CHECK( mig.num_gates() == 2u ); + CHECK( mig.num_pis() == 4u ); + CHECK( mig.num_pos() == 1u ); + + const auto tt = simulate>( mig )[0]; + CHECK( tt._bits == 0x8 ); +} + +TEST_CASE( "encode mig_network into mig_index_list", "[index_list]" ) +{ + mig_network mig; + auto const a = mig.create_pi(); + auto const b = mig.create_pi(); + auto const c = mig.create_pi(); + auto const d = mig.create_pi(); + auto const t0 = mig.create_maj( a, b, c ); + auto const t1 = mig.create_maj( t0, b, d ); + mig.create_po( t1 ); + + mig_index_list mig_il; + encode( mig_il, mig ); + + CHECK( mig_il.num_pis() == 4u ); + CHECK( mig_il.num_pos() == 1u ); + CHECK( mig_il.num_entries() == 2u ); + CHECK( mig_il.size() == 9u ); + CHECK( mig_il.raw() == std::vector{4, 1, 2, 4, 6, 4, 8, 10, 12} ); +} From 57f6283807730879465d0202bb2e53897dec7e86 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 12 Oct 2020 15:49:53 +0200 Subject: [PATCH 02/14] mig_index_list. --- include/mockturtle/utils/index_list.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 206d50118..24dae2e14 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -121,7 +121,7 @@ struct mig_index_list std::vector values; }; -/*! \brief Generates a network from an index_list */ +/*! \brief Generates an mig_index_list from a network */ template void encode( mig_index_list& indices, Ntk const& ntk ) { @@ -136,6 +136,8 @@ void encode( mig_index_list& indices, Ntk const& ntk ) /* gates */ ntk.foreach_gate( [&]( node const& n ){ + assert( ntk.is_maj( n ) ); + std::array lits; ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); @@ -151,7 +153,7 @@ void encode( mig_index_list& indices, Ntk const& ntk ) assert( indices.size() == 2u + 3u*ntk.num_gates() + ntk.num_pos() ); } -/*! \brief Generates a network from an mig_index_list */ +/*! \brief Generates a network from a mig_index_list */ template void decode( Ntk& ntk, mig_index_list const& indices ) { From 4abfca9a4c24966d84f02ce06f4dea9e0c3ba275 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 12 Oct 2020 16:17:14 +0200 Subject: [PATCH 03/14] mig_index_list. --- include/mockturtle/utils/index_list.hpp | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 24dae2e14..644384a47 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -39,7 +39,7 @@ namespace mockturtle /*! \brief Index list for majority-inverter graphs. * * Small network consisting of majority gates and inverters - * represented as a list of indices. + * represented as a list of literals. */ struct mig_index_list { @@ -47,9 +47,12 @@ struct mig_index_list using element_type = uint64_t; public: - explicit mig_index_list() + explicit mig_index_list( uint64_t num_pis = 0, uint64_t num_pos = 0 ) : values( 2u, 0u ) - {} + { + values[0u] = num_pis; + values[1u] = num_pos; + } explicit mig_index_list( std::vector const& values ) : values( std::begin( values ), std::end( values ) ) @@ -99,9 +102,9 @@ struct mig_index_list } } - void add_input() + void add_inputs( uint64_t num_pis = 1u ) { - ++values.at( 0u ); + values.at( 0u ) += num_pis ; } void add_gate( element_type lit0, element_type lit1, element_type lit2 ) @@ -121,7 +124,8 @@ struct mig_index_list std::vector values; }; -/*! \brief Generates an mig_index_list from a network */ +/*! \brief Generates an mig_index_list from a network + */ template void encode( mig_index_list& indices, Ntk const& ntk ) { @@ -129,10 +133,7 @@ void encode( mig_index_list& indices, Ntk const& ntk ) using signal = typename Ntk::signal; /* inputs */ - for ( uint64_t i = 0; i < ntk.num_pis(); ++i ) - { - indices.add_input(); - } + indices.add_inputs( ntk.num_pis() ); /* gates */ ntk.foreach_gate( [&]( node const& n ){ @@ -153,7 +154,8 @@ void encode( mig_index_list& indices, Ntk const& ntk ) assert( indices.size() == 2u + 3u*ntk.num_gates() + ntk.num_pos() ); } -/*! \brief Generates a network from a mig_index_list */ +/*! \brief Generates a network from a mig_index_list + */ template void decode( Ntk& ntk, mig_index_list const& indices ) { @@ -169,7 +171,8 @@ void decode( Ntk& ntk, mig_index_list const& indices ) [&]( signal const& s ){ ntk.create_po( s ); }); } -/*! \brief Inserts a mig_index_list into an existing network */ +/*! \brief Inserts a mig_index_list into an existing network + */ template void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indices, Fn&& fn ) { From b890499198ab9cad8e94fdf5c154ff753e5ce243 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 12 Oct 2020 16:44:42 +0200 Subject: [PATCH 04/14] mig_index_list. --- include/mockturtle/utils/index_list.hpp | 42 ++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 644384a47..31ede2439 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -48,11 +48,8 @@ struct mig_index_list public: explicit mig_index_list( uint64_t num_pis = 0, uint64_t num_pos = 0 ) - : values( 2u, 0u ) - { - values[0u] = num_pis; - values[1u] = num_pos; - } + : values( {num_pis, num_pos} ) + {} explicit mig_index_list( std::vector const& values ) : values( std::begin( values ), std::end( values ) ) @@ -125,6 +122,22 @@ struct mig_index_list }; /*! \brief Generates an mig_index_list from a network + * + * The function requires `ntk` to consist of majority gates. + * + * **Required network functions:** + * - `foreach_fanin` + * - `foreach_gate` + * - `get_node` + * - `is_complemented` + * - `is_maj` + * - `node_to_index` + * - `num_gates` + * - `num_pis` + * - `num_pos` + * + * \param indices An index list + * \param ntk A logic network */ template void encode( mig_index_list& indices, Ntk const& ntk ) @@ -155,6 +168,15 @@ void encode( mig_index_list& indices, Ntk const& ntk ) } /*! \brief Generates a network from a mig_index_list + * + * **Required network functions:** + * - `create_maj` + * - `create_pi` + * - `create_po` + * - `get_constant` + * + * \param ntk A logic network + * \param indices An index list */ template void decode( Ntk& ntk, mig_index_list const& indices ) @@ -172,6 +194,16 @@ void decode( Ntk& ntk, mig_index_list const& indices ) } /*! \brief Inserts a mig_index_list into an existing network + * + * **Required network functions:** + * - `get_constant` + * - `create_maj` + * + * \param ntk A logic network + * \param begin Begin iterator of signal inputs + * \param end End iterator of signal inputs + * \param indices An index list + * \param fn Callback function */ template void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indices, Fn&& fn ) From d1f22b11dee82ffc043e971dab5719a29cca2fa9 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Mon, 12 Oct 2020 17:34:47 +0200 Subject: [PATCH 05/14] abc_index_list. --- include/mockturtle/utils/index_list.hpp | 283 +++++++++++++++++++++--- test/utils/index_list.cpp | 44 +++- 2 files changed, 296 insertions(+), 31 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 31ede2439..6d063a288 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -36,6 +36,233 @@ namespace mockturtle { +/*! \brief An ABC-compatiable index list. + * + * Small network represented as a list of literals. The + * implementation supports AND and XOR gates and is compatiable with + * ABC's encoding. + */ +struct abc_index_list +{ +public: + using element_type = uint64_t; + +public: + explicit abc_index_list( uint64_t num_pis = 0 ) + : _num_pis( num_pis ) + , values( /* add constant */{ 0u, 1u } ) + {} + + explicit abc_index_list( std::vector const& values ) + : values( std::begin( values ), std::end( values ) ) + { + /* parse the values to determine the number of inputs and outputs */ + auto i = 2u; + for ( ; ( i+1 ) < values.size(); i+=2 ) + { + if ( values.at( i ) == 0 && values.at( i + 1 ) == 0 ) + { + ++_num_pis; + } + else + { + break; + } + } + + for ( ; ( i+1 ) < values.size(); i+=2 ) + { + assert( !( values.at( i ) == 0 && values.at( i + 1 ) == 0 ) ); + if ( values.at( i ) == values.at( i+1 ) ) + { + ++_num_pos; + } + } + } + + std::vector raw() const + { + return values; + } + + uint64_t size() const + { + return values.size(); + } + + uint64_t num_entries() const + { + return ( values.size() - ( ( 1 + _num_pis + _num_pos ) << 1u ) ) >> 1u; + } + + uint64_t num_pis() const + { + return _num_pis; + } + + uint64_t num_pos() const + { + return _num_pos; + } + + template + void foreach_entry( Fn&& fn ) const + { + assert( ( values.size() % 2 ) == 0 ); + for ( uint64_t i = ( 1 + _num_pis ) << 1u; i < values.size() - ( _num_pos << 1 ); i += 2 ) + { + fn( values.at( i ), values.at( i+1 ) ); + } + } + + template + void foreach_po( Fn&& fn ) const + { + for ( uint64_t i = values.size() - _num_pos; i < values.size(); ++i ) + { + fn( values.at( i ) ); + } + } + + void add_inputs( uint64_t num_pis = 1u ) + { + _num_pis += num_pis; + for ( auto i = 0u; i < num_pis; ++i ) + { + values.push_back( 0u ); + values.push_back( 0u ); + } + } + + void add_and( element_type lit0, element_type lit1 ) + { + assert( lit0 < lit1 ); + values.push_back( lit0 ); + values.push_back( lit1 ); + } + + void add_xor( element_type lit0, element_type lit1 ) + { + assert( lit0 > lit1 ); + values.push_back( lit0 ); + values.push_back( lit1 ); + } + + void add_output( element_type lit ) + { + ++_num_pos; + values.push_back( lit ); + values.push_back( lit ); + } + +private: + uint64_t _num_pis{0}; + uint64_t _num_pos{0}; + std::vector values; +}; + +/*! \brief Generates an abc_index_list from a network + * + * **Required network functions:** + * - `foreach_fanin` + * - `foreach_gate` + * - `get_node` + * - `is_complemented` + * - `is_and` + * - `is_xor` + * - `node_to_index` + * - `num_gates` + * - `num_pis` + * - `num_pos` + * + * \param indices An index list + * \param ntk A logic network + */ +template +void encode( abc_index_list& indices, Ntk const& ntk ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + /* inputs */ + indices.add_inputs( ntk.num_pis() ); + + /* gates */ + ntk.foreach_gate( [&]( node const& n ){ + assert( ntk.is_and( n ) || ntk.is_xor( n ) ); + + std::array lits; + ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); + }); + + if ( ntk.is_and( n ) ) + { + indices.add_and( lits[0u], lits[1u] ); + } + else if ( ntk.is_xor( n ) ) + { + indices.add_xor( lits[0u], lits[1u] ); + } + }); + + /* outputs */ + ntk.foreach_po( [&]( signal const& f ){ + indices.add_output( 2*ntk.node_to_index( ntk.get_node( f ) ) + ntk.is_complemented( f ) ); + }); + + assert( indices.size() == ( 1u + ntk.num_pis() + ntk.num_gates() + ntk.num_pos() ) << 1u ); +} + +/*! \brief Inserts an abc_index_list into an existing network + * + * **Required network functions:** + * - `get_constant` + * - `create_and` + * - `create_xor` + * + * \param ntk A logic network + * \param begin Begin iterator of signal inputs + * \param end End iterator of signal inputs + * \param indices An index list + * \param fn Callback function + */ +template +void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indices, Fn&& fn ) +{ + using signal = typename Ntk::signal; + + std::vector signals; + signals.emplace_back( ntk.get_constant( false ) ); + for ( auto it = begin; it != end; ++it ) + { + signals.push_back( *it ); + } + + indices.foreach_entry( [&]( uint64_t lit0, uint64_t lit1 ){ + assert( lit0 != lit1 ); + + uint64_t const i0 = lit0 >> 1; + uint64_t const i1 = lit1 >> 1; + signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); + signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); + + if ( lit0 < lit1 ) + { + signals.push_back( ntk.create_and( s0, s1 ) ); + } + else if ( lit0 > lit1 ) + { + signals.push_back( ntk.create_xor( s0, s1 ) ); + } + }); + + indices.foreach_po( [&]( uint64_t lit ){ + uint64_t const i = lit >> 1; + fn( ( lit % 2 ) ? !signals.at( i ) : signals.at( i ) ); + }); +} + /*! \brief Index list for majority-inverter graphs. * * Small network consisting of majority gates and inverters @@ -47,8 +274,8 @@ struct mig_index_list using element_type = uint64_t; public: - explicit mig_index_list( uint64_t num_pis = 0, uint64_t num_pos = 0 ) - : values( {num_pis, num_pos} ) + explicit mig_index_list( uint64_t num_pis = 0 ) + : values( {num_pis, 0u} ) {} explicit mig_index_list( std::vector const& values ) @@ -121,7 +348,7 @@ struct mig_index_list std::vector values; }; -/*! \brief Generates an mig_index_list from a network +/*! \brief Generates a mig_index_list from a network * * The function requires `ntk` to consist of majority gates. * @@ -167,32 +394,6 @@ void encode( mig_index_list& indices, Ntk const& ntk ) assert( indices.size() == 2u + 3u*ntk.num_gates() + ntk.num_pos() ); } -/*! \brief Generates a network from a mig_index_list - * - * **Required network functions:** - * - `create_maj` - * - `create_pi` - * - `create_po` - * - `get_constant` - * - * \param ntk A logic network - * \param indices An index list - */ -template -void decode( Ntk& ntk, mig_index_list const& indices ) -{ - using signal = typename Ntk::signal; - - std::vector signals; - for ( uint64_t i = 0; i < indices.num_pis(); ++i ) - { - signals.push_back( ntk.create_pi() ); - } - - insert( ntk, std::begin( signals ), std::end( signals ), indices, - [&]( signal const& s ){ ntk.create_po( s ); }); -} - /*! \brief Inserts a mig_index_list into an existing network * * **Required network functions:** @@ -233,4 +434,28 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic }); } +/*! \brief Generates a network from an index_list + * + * **Required network functions:** + * - `create_pi` + * - `create_po` + * + * \param ntk A logic network + * \param indices An index list + */ +template +void decode( Ntk& ntk, IndexList const& indices ) +{ + using signal = typename Ntk::signal; + + std::vector signals; + for ( uint64_t i = 0; i < indices.num_pis(); ++i ) + { + signals.push_back( ntk.create_pi() ); + } + + insert( ntk, std::begin( signals ), std::end( signals ), indices, + [&]( signal const& s ){ ntk.create_po( s ); }); +} + } /* mockturtle */ diff --git a/test/utils/index_list.cpp b/test/utils/index_list.cpp index bafbec50f..30a12d244 100644 --- a/test/utils/index_list.cpp +++ b/test/utils/index_list.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -19,8 +20,8 @@ TEST_CASE( "decode mig_index_list into mig_network", "[index_list]" ) CHECK( mig.num_pis() == 4u ); CHECK( mig.num_pos() == 1u ); - const auto tt = simulate>( mig )[0]; - CHECK( tt._bits == 0x8 ); + const auto tt = simulate>( mig )[0]; + CHECK( tt._bits == 0xecc8 ); } TEST_CASE( "encode mig_network into mig_index_list", "[index_list]" ) @@ -43,3 +44,42 @@ TEST_CASE( "encode mig_network into mig_index_list", "[index_list]" ) CHECK( mig_il.size() == 9u ); CHECK( mig_il.raw() == std::vector{4, 1, 2, 4, 6, 4, 8, 10, 12} ); } + +TEST_CASE( "decode abc_index_list into xag_network", "[index_list]" ) +{ + std::vector const raw_list{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}; + abc_index_list xag_il{raw_list}; + + xag_network xag; + decode( xag, xag_il ); + + CHECK( xag.num_gates() == 3u ); + CHECK( xag.num_pis() == 4u ); + CHECK( xag.num_pos() == 1u ); + + const auto tt = simulate>( xag )[0]; + CHECK( tt._bits == 0x7888 ); +} + +TEST_CASE( "encode xag_network into abc_index_list", "[index_list]" ) +{ + xag_network xag; + auto const a = xag.create_pi(); + auto const b = xag.create_pi(); + auto const c = xag.create_pi(); + auto const d = xag.create_pi(); + auto const t0 = xag.create_and( a, b ); + auto const t1 = xag.create_and( c, d ); + auto const t2 = xag.create_xor( t0, t1 ); + xag.create_po( t2 ); + + abc_index_list xag_il; + encode( xag_il, xag ); + + CHECK( xag_il.num_pis() == 4u ); + CHECK( xag_il.num_pos() == 1u ); + CHECK( xag_il.num_entries() == 3u ); + CHECK( xag_il.size() == 18u ); + CHECK( xag_il.raw() == std::vector{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14} ); +} + From 41e2e2b252fdcdc67f3580a165f8eb7826446a8d Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 13 Oct 2020 18:28:27 +0200 Subject: [PATCH 06/14] index_list: more compact encoding. --- include/mockturtle/utils/index_list.hpp | 79 +++++++++++++------------ test/utils/index_list.cpp | 14 ++--- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 6d063a288..e564eece5 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -45,10 +45,10 @@ namespace mockturtle struct abc_index_list { public: - using element_type = uint64_t; + using element_type = uint32_t; public: - explicit abc_index_list( uint64_t num_pis = 0 ) + explicit abc_index_list( uint32_t num_pis = 0 ) : _num_pis( num_pis ) , values( /* add constant */{ 0u, 1u } ) {} @@ -90,7 +90,7 @@ struct abc_index_list return values.size(); } - uint64_t num_entries() const + uint64_t num_gates() const { return ( values.size() - ( ( 1 + _num_pis + _num_pos ) << 1u ) ) >> 1u; } @@ -124,7 +124,7 @@ struct abc_index_list } } - void add_inputs( uint64_t num_pis = 1u ) + void add_inputs( uint32_t num_pis = 1u ) { _num_pis += num_pis; for ( auto i = 0u; i < num_pis; ++i ) @@ -156,9 +156,9 @@ struct abc_index_list } private: - uint64_t _num_pis{0}; - uint64_t _num_pos{0}; - std::vector values; + uint32_t _num_pis{0}; + uint32_t _num_pos{0}; + std::vector values; }; /*! \brief Generates an abc_index_list from a network @@ -191,8 +191,8 @@ void encode( abc_index_list& indices, Ntk const& ntk ) ntk.foreach_gate( [&]( node const& n ){ assert( ntk.is_and( n ) || ntk.is_xor( n ) ); - std::array lits; - ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + std::array lits; + ntk.foreach_fanin( n, [&]( signal const& fi, uint32_t index ){ lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); }); @@ -239,11 +239,11 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic signals.push_back( *it ); } - indices.foreach_entry( [&]( uint64_t lit0, uint64_t lit1 ){ + indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1 ){ assert( lit0 != lit1 ); - uint64_t const i0 = lit0 >> 1; - uint64_t const i1 = lit1 >> 1; + uint32_t const i0 = lit0 >> 1; + uint32_t const i1 = lit1 >> 1; signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); @@ -257,8 +257,8 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic } }); - indices.foreach_po( [&]( uint64_t lit ){ - uint64_t const i = lit >> 1; + indices.foreach_po( [&]( uint32_t lit ){ + uint32_t const i = lit >> 1; fn( ( lit % 2 ) ? !signals.at( i ) : signals.at( i ) ); }); } @@ -271,12 +271,13 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic struct mig_index_list { public: - using element_type = uint64_t; + using element_type = uint32_t; public: - explicit mig_index_list( uint64_t num_pis = 0 ) - : values( {num_pis, 0u} ) - {} + explicit mig_index_list( uint32_t num_pis = 0 ) + : values( {num_pis} ) + { + } explicit mig_index_list( std::vector const& values ) : values( std::begin( values ), std::end( values ) ) @@ -292,26 +293,26 @@ struct mig_index_list return values.size(); } - uint64_t num_entries() const + uint64_t num_gates() const { - return ( values.size() - 2u - num_pos() ) / 3u; + return ( values.at( 0 ) >> 16 ); } uint64_t num_pis() const { - return values.at( 0u ); + return values.at( 0 ) & 0xff; } uint64_t num_pos() const { - return values.at( 1u ); + return ( values.at( 0 ) >> 8 ) & 0xff; } template void foreach_entry( Fn&& fn ) const { - assert( ( values.size() - 2u - num_pos() ) % 3 == 0 ); - for ( uint64_t i = 2u; i < values.size() - num_pos(); i += 3 ) + assert( ( values.size() - 1u - num_pos() ) % 3 == 0 ); + for ( uint64_t i = 1u; i < values.size() - num_pos(); i += 3 ) { fn( values.at( i ), values.at( i+1 ), values.at( i+2 ) ); } @@ -326,13 +327,16 @@ struct mig_index_list } } - void add_inputs( uint64_t num_pis = 1u ) + void add_inputs( uint32_t n = 1u ) { - values.at( 0u ) += num_pis ; + assert( num_pis() + n <= 0xff ); + values.at( 0u ) += n; } - void add_gate( element_type lit0, element_type lit1, element_type lit2 ) + void add_maj( element_type lit0, element_type lit1, element_type lit2 ) { + assert( num_gates() + 1u <= 0xffff ); + values.at( 0u ) = ( ( num_gates() + 1 ) << 16 ) | ( values.at( 0 ) & 0xffff ); values.push_back( lit0 ); values.push_back( lit1 ); values.push_back( lit2 ); @@ -340,7 +344,8 @@ struct mig_index_list void add_output( element_type lit ) { - ++values.at( 1u ); + assert( num_pos() + 1 <= 0xff ); + values.at( 0u ) = ( num_pos() + 1 ) << 8 | ( values.at( 0u ) & 0xffff00ff ); values.push_back( lit ); } @@ -379,11 +384,11 @@ void encode( mig_index_list& indices, Ntk const& ntk ) ntk.foreach_gate( [&]( node const& n ){ assert( ntk.is_maj( n ) ); - std::array lits; + std::array lits; ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); }); - indices.add_gate( lits[0u], lits[1u], lits[2u] ); + indices.add_maj( lits[0u], lits[1u], lits[2u] ); }); /* outputs */ @@ -391,7 +396,7 @@ void encode( mig_index_list& indices, Ntk const& ntk ) indices.add_output( 2*ntk.node_to_index( ntk.get_node( f ) ) + ntk.is_complemented( f ) ); }); - assert( indices.size() == 2u + 3u*ntk.num_gates() + ntk.num_pos() ); + assert( indices.size() == 1u + 3u*ntk.num_gates() + ntk.num_pos() ); } /*! \brief Inserts a mig_index_list into an existing network @@ -418,18 +423,18 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic signals.push_back( *it ); } - indices.foreach_entry( [&]( uint64_t lit0, uint64_t lit1, uint64_t lit2 ){ - uint64_t const i0 = lit0 >> 1; - uint64_t const i1 = lit1 >> 1; - uint64_t const i2 = lit2 >> 1; + indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1, uint32_t lit2 ){ + uint32_t const i0 = lit0 >> 1; + uint32_t const i1 = lit1 >> 1; + uint32_t const i2 = lit2 >> 1; signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); signal const s2 = ( lit2 % 2 ) ? !signals.at( i2 ) : signals.at( i2 ); signals.push_back( ntk.create_maj( s0, s1, s2 ) ); }); - indices.foreach_po( [&]( uint64_t lit ){ - uint64_t const i = lit >> 1; + indices.foreach_po( [&]( uint32_t lit ){ + uint32_t const i = lit >> 1; fn( ( lit % 2 ) ? !signals.at( i ) : signals.at( i ) ); }); } diff --git a/test/utils/index_list.cpp b/test/utils/index_list.cpp index 30a12d244..da1b99f4d 100644 --- a/test/utils/index_list.cpp +++ b/test/utils/index_list.cpp @@ -10,7 +10,7 @@ using namespace mockturtle; TEST_CASE( "decode mig_index_list into mig_network", "[index_list]" ) { - std::vector const raw_list{4, 1, 2, 4, 6, 10, 4, 8, 12}; + std::vector const raw_list{4 | ( 1 << 8 ) | ( 2 << 16 ), 2, 4, 6, 10, 4, 8, 12}; mig_index_list mig_il{raw_list}; mig_network mig; @@ -40,14 +40,14 @@ TEST_CASE( "encode mig_network into mig_index_list", "[index_list]" ) CHECK( mig_il.num_pis() == 4u ); CHECK( mig_il.num_pos() == 1u ); - CHECK( mig_il.num_entries() == 2u ); - CHECK( mig_il.size() == 9u ); - CHECK( mig_il.raw() == std::vector{4, 1, 2, 4, 6, 4, 8, 10, 12} ); + CHECK( mig_il.num_gates() == 2u ); + CHECK( mig_il.size() == 8u ); + CHECK( mig_il.raw() == std::vector{4 | ( 1 << 8 ) | ( 2 << 16 ), 2, 4, 6, 4, 8, 10, 12} ); } TEST_CASE( "decode abc_index_list into xag_network", "[index_list]" ) { - std::vector const raw_list{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}; + std::vector const raw_list{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}; abc_index_list xag_il{raw_list}; xag_network xag; @@ -78,8 +78,8 @@ TEST_CASE( "encode xag_network into abc_index_list", "[index_list]" ) CHECK( xag_il.num_pis() == 4u ); CHECK( xag_il.num_pos() == 1u ); - CHECK( xag_il.num_entries() == 3u ); + CHECK( xag_il.num_gates() == 3u ); CHECK( xag_il.size() == 18u ); - CHECK( xag_il.raw() == std::vector{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14} ); + CHECK( xag_il.raw() == std::vector{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14} ); } From f4a83aa0388ee23975629ef665e10510fe12b6d9 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 13 Oct 2020 18:40:27 +0200 Subject: [PATCH 07/14] xag_index_list. --- include/mockturtle/utils/index_list.hpp | 200 ++++++++++++++++++++++++ test/utils/index_list.cpp | 38 +++++ 2 files changed, 238 insertions(+) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index e564eece5..d1991817d 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -439,6 +439,206 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic }); } +/*! \brief Index list for xor-and graphs. + * + * Small network represented as a list of literals. Supports XOR and + * AND gates. + */ +struct xag_index_list +{ +public: + using element_type = uint32_t; + +public: + explicit xag_index_list( uint32_t num_pis = 0 ) + : values( {num_pis} ) + { + } + + explicit xag_index_list( std::vector const& values ) + : values( std::begin( values ), std::end( values ) ) + {} + + std::vector raw() const + { + return values; + } + + uint64_t size() const + { + return values.size(); + } + + uint64_t num_gates() const + { + return ( values.at( 0 ) >> 16 ); + } + + uint64_t num_pis() const + { + return values.at( 0 ) & 0xff; + } + + uint64_t num_pos() const + { + return ( values.at( 0 ) >> 8 ) & 0xff; + } + + template + void foreach_entry( Fn&& fn ) const + { + assert( ( values.size() - 1u - num_pos() ) % 2 == 0 ); + for ( uint64_t i = 1u; i < values.size() - num_pos(); i += 2 ) + { + fn( values.at( i ), values.at( i+1 ) ); + } + } + + template + void foreach_po( Fn&& fn ) const + { + for ( uint64_t i = values.size() - num_pos(); i < values.size(); ++i ) + { + fn( values.at( i ) ); + } + } + + void add_inputs( uint32_t n = 1u ) + { + assert( num_pis() + n <= 0xff ); + values.at( 0u ) += n; + } + + void add_and( element_type lit0, element_type lit1 ) + { + assert( num_gates() + 1u <= 0xffff ); + values.at( 0u ) = ( ( num_gates() + 1 ) << 16 ) | ( values.at( 0 ) & 0xffff ); + values.push_back( lit0 ); + values.push_back( lit1 ); + } + + void add_xor( element_type lit0, element_type lit1 ) + { + assert( num_gates() + 1u <= 0xffff ); + values.at( 0u ) = ( ( num_gates() + 1 ) << 16 ) | ( values.at( 0 ) & 0xffff ); + values.push_back( lit0 ); + values.push_back( lit1 ); + } + + void add_output( element_type lit ) + { + assert( num_pos() + 1 <= 0xff ); + values.at( 0u ) = ( num_pos() + 1 ) << 8 | ( values.at( 0u ) & 0xffff00ff ); + values.push_back( lit ); + } + +private: + std::vector values; +}; + +/*! \brief Generates a xag_index_list from a network + * + * The function requires `ntk` to consist of XOR and AND gates. + * + * **Required network functions:** + * - `foreach_fanin` + * - `foreach_gate` + * - `get_node` + * - `is_and` + * - `is_complemented` + * - `is_xor` + * - `node_to_index` + * - `num_gates` + * - `num_pis` + * - `num_pos` + * + * \param indices An index list + * \param ntk A logic network + */ +template +void encode( xag_index_list& indices, Ntk const& ntk ) +{ + using node = typename Ntk::node; + using signal = typename Ntk::signal; + + /* inputs */ + indices.add_inputs( ntk.num_pis() ); + + /* gates */ + ntk.foreach_gate( [&]( node const& n ){ + assert( ntk.is_and( n ) || ntk.is_xor( n ) ); + + std::array lits; + ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); + }); + + if ( ntk.is_and( n ) ) + { + indices.add_and( lits[0u], lits[1u] ); + } + else if ( ntk.is_xor( n ) ) + { + indices.add_xor( lits[0u], lits[1u] ); + } + }); + + /* outputs */ + ntk.foreach_po( [&]( signal const& f ){ + indices.add_output( 2*ntk.node_to_index( ntk.get_node( f ) ) + ntk.is_complemented( f ) ); + }); + + assert( indices.size() == 1u + 2u*ntk.num_gates() + ntk.num_pos() ); +} + +/*! \brief Inserts a xag_index_list into an existing network + * + * **Required network functions:** + * - `get_constant` + * - `create_maj` + * + * \param ntk A logic network + * \param begin Begin iterator of signal inputs + * \param end End iterator of signal inputs + * \param indices An index list + * \param fn Callback function + */ +template +void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indices, Fn&& fn ) +{ + using signal = typename Ntk::signal; + + std::vector signals; + signals.emplace_back( ntk.get_constant( false ) ); + for ( auto it = begin; it != end; ++it ) + { + signals.push_back( *it ); + } + + indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1 ){ + assert( lit0 != lit1 ); + + uint32_t const i0 = lit0 >> 1; + uint32_t const i1 = lit1 >> 1; + signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); + signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); + + if ( lit0 < lit1 ) + { + signals.push_back( ntk.create_and( s0, s1 ) ); + } + else if ( lit0 > lit1 ) + { + signals.push_back( ntk.create_xor( s0, s1 ) ); + } + }); + + indices.foreach_po( [&]( uint32_t lit ){ + uint32_t const i = lit >> 1; + fn( ( lit % 2 ) ? !signals.at( i ) : signals.at( i ) ); + }); +} + /*! \brief Generates a network from an index_list * * **Required network functions:** diff --git a/test/utils/index_list.cpp b/test/utils/index_list.cpp index da1b99f4d..f96485ee4 100644 --- a/test/utils/index_list.cpp +++ b/test/utils/index_list.cpp @@ -83,3 +83,41 @@ TEST_CASE( "encode xag_network into abc_index_list", "[index_list]" ) CHECK( xag_il.raw() == std::vector{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14} ); } +TEST_CASE( "decode xag_index_list into xag_network", "[index_list]" ) +{ + std::vector const raw_list{4 | ( 1 << 8 ) | ( 3 << 16 ), 2, 4, 6, 8, 12, 10, 14}; + xag_index_list xag_il{raw_list}; + + xag_network xag; + decode( xag, xag_il ); + + CHECK( xag.num_gates() == 3u ); + CHECK( xag.num_pis() == 4u ); + CHECK( xag.num_pos() == 1u ); + + const auto tt = simulate>( xag )[0]; + CHECK( tt._bits == 0x7888 ); +} + +TEST_CASE( "encode xag_network into xag_index_list", "[index_list]" ) +{ + xag_network xag; + auto const a = xag.create_pi(); + auto const b = xag.create_pi(); + auto const c = xag.create_pi(); + auto const d = xag.create_pi(); + auto const t0 = xag.create_and( a, b ); + auto const t1 = xag.create_and( c, d ); + auto const t2 = xag.create_xor( t0, t1 ); + xag.create_po( t2 ); + + xag_index_list xag_il; + encode( xag_il, xag ); + + CHECK( xag_il.num_pis() == 4u ); + CHECK( xag_il.num_pos() == 1u ); + CHECK( xag_il.num_gates() == 3u ); + CHECK( xag_il.size() == 8u ); + CHECK( xag_il.raw() == std::vector{4 | ( 1 << 8 ) | ( 3 << 16 ), 2, 4, 6, 8, 12, 10, 14} ); +} + From a93f4cf4071695850245796d38079b755c9f7e61 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 13 Oct 2020 20:31:23 +0200 Subject: [PATCH 08/14] index_list: more documentation and checks. --- include/mockturtle/utils/index_list.hpp | 175 ++++++++++++++++++++---- 1 file changed, 152 insertions(+), 23 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index d1991817d..7b86769ea 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -29,7 +29,10 @@ \author Heinz Riener */ +#include "../traits.hpp" + #include + #include #include @@ -41,6 +44,10 @@ namespace mockturtle * Small network represented as a list of literals. The * implementation supports AND and XOR gates and is compatiable with * ABC's encoding. + * + * Example: The following index list creates the output function `(x1 + * AND x2) XOR (x3 AND x4)` with 4 inputs, 1 output, and 3 gates: + * `{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}` */ struct abc_index_list { @@ -167,8 +174,8 @@ struct abc_index_list * - `foreach_fanin` * - `foreach_gate` * - `get_node` - * - `is_complemented` * - `is_and` + * - `is_complemented` * - `is_xor` * - `node_to_index` * - `num_gates` @@ -181,18 +188,48 @@ struct abc_index_list template void encode( abc_index_list& indices, Ntk const& ntk ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_foreach_fanin_v, "Ntk does not implement the foreach_fanin method" ); + static_assert( has_foreach_gate_v, "Ntk does not implement the foreach_gate method" ); + static_assert( has_is_and_v, "Ntk does not implement the is_and method" ); + static_assert( has_get_node_v, "Ntk does not implement the get_node method" ); + static_assert( has_is_complemented_v, "Ntk does not implement the is_complemented method" ); + static_assert( has_is_xor_v, "Ntk does not implement the is_xor method" ); + static_assert( has_node_to_index_v, "Ntk does not implement the node_to_index method" ); + static_assert( has_num_gates_v, "Ntk does not implement the num_gates method" ); + static_assert( has_num_pis_v, "Ntk does not implement the num_pis method" ); + static_assert( has_num_pos_v, "Ntk does not implement the num_pos method" ); + using node = typename Ntk::node; using signal = typename Ntk::signal; + ntk.foreach_pi( [&]( node const& n, uint64_t i ) { + if ( ntk.node_to_index( n ) != i + 1 ) + { + fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", i + 1 ); + std::abort(); + } + }); + /* inputs */ indices.add_inputs( ntk.num_pis() ); /* gates */ - ntk.foreach_gate( [&]( node const& n ){ + ntk.foreach_gate( [&]( node const& n, uint64_t index ){ assert( ntk.is_and( n ) || ntk.is_xor( n ) ); + if ( ntk.node_to_index( n ) != ntk.num_pis() + index + 1 ) + { + fmt::print( "[e] network is not in normalized index order (violated by node {})\n", ntk.node_to_index( n ) ); + std::abort(); + } std::array lits; - ntk.foreach_fanin( n, [&]( signal const& fi, uint32_t index ){ + ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + if ( ntk.node_to_index( ntk.get_node( fi ) ) > ntk.node_to_index( n ) ) + { + fmt::print( "[e] node {} not in topological order\n", ntk.node_to_index( n ) ); + std::abort(); + } lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); }); @@ -230,6 +267,14 @@ void encode( abc_index_list& indices, Ntk const& ntk ) template void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indices, Fn&& fn ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_create_and_v, "Ntk does not implement the create_and method" ); + static_assert( has_create_xor_v, "Ntk does not implement the create_xor method" ); + static_assert( has_get_constant_v, "Ntk does not implement the get_constant method" ); + + static_assert( std::is_same_v::value_type>, signal>, "BeginIter value_type must be Ntk signal type" ); + static_assert( std::is_same_v::value_type>, signal>, "EndIter value_type must be Ntk signal type" ); + using signal = typename Ntk::signal; std::vector signals; @@ -247,14 +292,7 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); - if ( lit0 < lit1 ) - { - signals.push_back( ntk.create_and( s0, s1 ) ); - } - else if ( lit0 > lit1 ) - { - signals.push_back( ntk.create_xor( s0, s1 ) ); - } + signals.push_back( lit0 < lit1 ? ntk.create_and( s0, s1 ) : ntk.create_xor( s0, s1 ) ); }); indices.foreach_po( [&]( uint32_t lit ){ @@ -267,6 +305,10 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic * * Small network consisting of majority gates and inverters * represented as a list of literals. + * + * Example: The following index list creates the output function + * `<, x2, x4>` with 4 inputs, 1 output, and 3 gates: + * `{4 | 1 << 8 | 2 << 16, 2, 4, 6, 4, 8, 10, 12}` */ struct mig_index_list { @@ -374,18 +416,47 @@ struct mig_index_list template void encode( mig_index_list& indices, Ntk const& ntk ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_foreach_fanin_v, "Ntk does not implement the foreach_fanin method" ); + static_assert( has_foreach_gate_v, "Ntk does not implement the foreach_gate method" ); + static_assert( has_get_node_v, "Ntk does not implement the get_node method" ); + static_assert( has_is_complemented_v, "Ntk does not implement the is_complemented method" ); + static_assert( has_is_maj_v, "Ntk does not implement the is_maj method" ); + static_assert( has_node_to_index_v, "Ntk does not implement the node_to_index method" ); + static_assert( has_num_gates_v, "Ntk does not implement the num_gates method" ); + static_assert( has_num_pis_v, "Ntk does not implement the num_pis method" ); + static_assert( has_num_pos_v, "Ntk does not implement the num_pos method" ); + using node = typename Ntk::node; using signal = typename Ntk::signal; + ntk.foreach_pi( [&]( node const& n, uint64_t index ) { + if ( ntk.node_to_index( n ) != index + 1 ) + { + fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", index + 1 ); + std::abort(); + } + }); + /* inputs */ indices.add_inputs( ntk.num_pis() ); /* gates */ - ntk.foreach_gate( [&]( node const& n ){ + ntk.foreach_gate( [&]( node const& n, uint64_t index ){ assert( ntk.is_maj( n ) ); + if ( ntk.node_to_index( n ) != ntk.num_pis() + index + 1 ) + { + fmt::print( "[e] network is not in normalized index order (violated by node {})\n", ntk.node_to_index( n ) ); + std::abort(); + } std::array lits; ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + if ( ntk.node_to_index( ntk.get_node( fi ) ) > ntk.node_to_index( n ) ) + { + fmt::print( "[e] node {} not in topological order\n", ntk.node_to_index( n ) ); + std::abort(); + } lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); }); indices.add_maj( lits[0u], lits[1u], lits[2u] ); @@ -414,6 +485,13 @@ void encode( mig_index_list& indices, Ntk const& ntk ) template void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indices, Fn&& fn ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_create_maj_v, "Ntk does not implement the create_maj method" ); + static_assert( has_get_constant_v, "Ntk does not implement the get_constant method" ); + + static_assert( std::is_same_v::value_type>, signal>, "BeginIter value_type must be Ntk signal type" ); + static_assert( std::is_same_v::value_type>, signal>, "EndIter value_type must be Ntk signal type" ); + using signal = typename Ntk::signal; std::vector signals; @@ -442,7 +520,22 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic /*! \brief Index list for xor-and graphs. * * Small network represented as a list of literals. Supports XOR and - * AND gates. + * AND gates. The list has the following 32-bit unsigned integer + * elements. It starts with a signature whose partitioned into `| + * num_gates | num_pos | num_pis |`, where `num_gates` accounts for + * the most-significant 16 bits, `num_pos` accounts for 8 bits, and + * `num_pis` accounts for the least-significant 8 bits. Afterwards, + * gates are defined as literal indexes `(2 * i + c)`, where `i` is an + * index, with 0 indexing the constant 0, 1 to `num_pis` indexing the + * primary inputs, and all successive indexes for the gates. Gate + * literals come in pairs. If the first literal has a smaller value + * than the second one, an AND gate is created, otherwise, an XOR gate + * is created. Afterwards, all outputs are defined in terms of + * literals. + * + * Example: The following index list creates the output function `(x1 + * AND x2) XOR (x3 AND x4)` with 4 inputs, 1 output, and 3 gates: + * `{4 | 1 << 8 | 3 << 16, 2, 4, 6, 8, 12, 10, 14}` */ struct xag_index_list { @@ -558,18 +651,48 @@ struct xag_index_list template void encode( xag_index_list& indices, Ntk const& ntk ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_foreach_fanin_v, "Ntk does not implement the foreach_fanin method" ); + static_assert( has_foreach_gate_v, "Ntk does not implement the foreach_gate method" ); + static_assert( has_is_and_v, "Ntk does not implement the is_and method" ); + static_assert( has_get_node_v, "Ntk does not implement the get_node method" ); + static_assert( has_is_complemented_v, "Ntk does not implement the is_complemented method" ); + static_assert( has_is_xor_v, "Ntk does not implement the is_xor method" ); + static_assert( has_node_to_index_v, "Ntk does not implement the node_to_index method" ); + static_assert( has_num_gates_v, "Ntk does not implement the num_gates method" ); + static_assert( has_num_pis_v, "Ntk does not implement the num_pis method" ); + static_assert( has_num_pos_v, "Ntk does not implement the num_pos method" ); + using node = typename Ntk::node; using signal = typename Ntk::signal; + ntk.foreach_pi( [&]( node const& n, uint64_t index ) { + if ( ntk.node_to_index( n ) != index + 1 ) + { + fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", index + 1 ); + std::abort(); + } + }); + /* inputs */ indices.add_inputs( ntk.num_pis() ); /* gates */ - ntk.foreach_gate( [&]( node const& n ){ + ntk.foreach_gate( [&]( node const& n, uint64_t index ){ assert( ntk.is_and( n ) || ntk.is_xor( n ) ); + if ( ntk.node_to_index( n ) != ntk.num_pis() + index + 1 ) + { + fmt::print( "[e] network is not in normalized index order (violated by node {})\n", ntk.node_to_index( n ) ); + std::abort(); + } std::array lits; ntk.foreach_fanin( n, [&]( signal const& fi, uint64_t index ){ + if ( ntk.node_to_index( ntk.get_node( fi ) ) > ntk.node_to_index( n ) ) + { + fmt::print( "[e] node {} not in topological order\n", ntk.node_to_index( n ) ); + std::abort(); + } lits[index] = 2*ntk.node_to_index( ntk.get_node( fi ) ) + ntk.is_complemented( fi ); }); @@ -594,8 +717,9 @@ void encode( xag_index_list& indices, Ntk const& ntk ) /*! \brief Inserts a xag_index_list into an existing network * * **Required network functions:** + * - `create_and` + * - `create_xor` * - `get_constant` - * - `create_maj` * * \param ntk A logic network * \param begin Begin iterator of signal inputs @@ -606,6 +730,14 @@ void encode( xag_index_list& indices, Ntk const& ntk ) template void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indices, Fn&& fn ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_create_and_v, "Ntk does not implement the create_and method" ); + static_assert( has_create_xor_v, "Ntk does not implement the create_xor method" ); + static_assert( has_get_constant_v, "Ntk does not implement the get_constant method" ); + + static_assert( std::is_same_v::value_type>, signal>, "BeginIter value_type must be Ntk signal type" ); + static_assert( std::is_same_v::value_type>, signal>, "EndIter value_type must be Ntk signal type" ); + using signal = typename Ntk::signal; std::vector signals; @@ -623,14 +755,7 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indic signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); - if ( lit0 < lit1 ) - { - signals.push_back( ntk.create_and( s0, s1 ) ); - } - else if ( lit0 > lit1 ) - { - signals.push_back( ntk.create_xor( s0, s1 ) ); - } + signals.push_back( lit0 < lit1 ? ntk.create_and( s0, s1 ) : ntk.create_xor( s0, s1 ) ); }); indices.foreach_po( [&]( uint32_t lit ){ @@ -651,6 +776,10 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indic template void decode( Ntk& ntk, IndexList const& indices ) { + static_assert( is_network_type_v, "Ntk is not a network type" ); + static_assert( has_create_pi_v, "Ntk does not implement the create_pi method" ); + static_assert( has_create_po_v, "Ntk does not implement the create_po method" ); + using signal = typename Ntk::signal; std::vector signals; From 7309c8e13e7e63125ab86f2bb8982f43b84567ca Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Tue, 13 Oct 2020 20:44:11 +0200 Subject: [PATCH 09/14] minmc_xags tests. --- .../node_resynthesis/xag_minmc2.hpp | 12 ++++++-- .../algorithms/node_resynthesis/xag_npn.hpp | 4 +-- include/mockturtle/utils/index_list.hpp | 22 +++++++------- test/algorithms/equivalence_classes.cpp | 10 +++++-- test/io/index_list.cpp | 29 ++++--------------- 5 files changed, 37 insertions(+), 40 deletions(-) diff --git a/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp b/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp index c2390e9bd..9ff27459b 100644 --- a/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp +++ b/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp @@ -38,7 +38,7 @@ #include #include -#include "../../io/index_list.hpp" +#include "../../utils/index_list.hpp" #include "../../networks/xag.hpp" #include "../detail/minmc_xags.hpp" #include "../equivalence_classes.hpp" @@ -126,7 +126,15 @@ class xag_minmc_resynthesis } const auto f = apply_spectral_transformations( ntk, trans, std::vector>( begin, end ), [&]( xag_network& ntk, std::vector> const& leaves ) { - return create_from_binary_index_list( ntk, it->second.begin(), leaves.begin() )[0u]; + xag_index_list il{it->second}; + std::vector pos; + insert( ntk, std::begin( leaves ), std::begin( leaves ) + il.num_pis(), il, + [&]( xag_network::signal const& f ) + { + pos.push_back( f ); + } ); + assert( pos.size() == 1u ); + return pos[0u]; } ); fn( f ); diff --git a/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp b/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp index 2000d199a..6e358cd53 100644 --- a/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp +++ b/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp @@ -44,8 +44,8 @@ #include #include "../../algorithms/simulation.hpp" -#include "../../io/index_list.hpp" #include "../../networks/xag.hpp" +#include "../../utils/index_list.hpp" #include "../../utils/node_map.hpp" #include "../../utils/stopwatch.hpp" @@ -210,7 +210,7 @@ class xag_npn_resynthesis { stopwatch t( st.time_db ); - _db = create_from_binary_index_list( subgraphs ); + decode( _db, xag_index_list{std::vector( subgraphs, subgraphs + sizeof subgraphs / sizeof subgraphs[0] )} ); const auto sim_res = simulate_nodes>( _db ); _db.foreach_node( [&]( auto n ) { diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 7b86769ea..ccb4da209 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -29,6 +29,8 @@ \author Heinz Riener */ +#pragma once + #include "../traits.hpp" #include @@ -738,6 +740,8 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indic static_assert( std::is_same_v::value_type>, signal>, "BeginIter value_type must be Ntk signal type" ); static_assert( std::is_same_v::value_type>, signal>, "EndIter value_type must be Ntk signal type" ); + assert( uint64_t( std::distance( begin, end ) ) == indices.num_pis() ); + using signal = typename Ntk::signal; std::vector signals; @@ -749,18 +753,16 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indic indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1 ){ assert( lit0 != lit1 ); - uint32_t const i0 = lit0 >> 1; uint32_t const i1 = lit1 >> 1; - signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); - signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); - - signals.push_back( lit0 < lit1 ? ntk.create_and( s0, s1 ) : ntk.create_xor( s0, s1 ) ); + signal const s0 = ( lit0 % 2 ) ? ntk.create_not( signals.at( i0 ) ) : signals.at( i0 ); + signal const s1 = ( lit1 % 2 ) ? ntk.create_not( signals.at( i1 ) ) : signals.at( i1 ); + signals.push_back( lit0 > lit1 ? ntk.create_xor( s0, s1 ) : ntk.create_and( s0, s1 ) ); }); indices.foreach_po( [&]( uint32_t lit ){ uint32_t const i = lit >> 1; - fn( ( lit % 2 ) ? !signals.at( i ) : signals.at( i ) ); + fn( ( lit % 2 ) ? ntk.create_not( signals.at( i ) ) : signals.at( i ) ); }); } @@ -782,11 +784,9 @@ void decode( Ntk& ntk, IndexList const& indices ) using signal = typename Ntk::signal; - std::vector signals; - for ( uint64_t i = 0; i < indices.num_pis(); ++i ) - { - signals.push_back( ntk.create_pi() ); - } + std::vector signals( indices.num_pis() ); + std::generate( std::begin( signals ), std::end( signals ), + [&]() { return ntk.create_pi(); }); insert( ntk, std::begin( signals ), std::end( signals ), indices, [&]( signal const& s ){ ntk.create_po( s ); }); diff --git a/test/algorithms/equivalence_classes.cpp b/test/algorithms/equivalence_classes.cpp index afd091cf7..0690eeb2a 100644 --- a/test/algorithms/equivalence_classes.cpp +++ b/test/algorithms/equivalence_classes.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,7 @@ TEST_CASE( "Synthesize from database for 4-input functions", "[equivalence_class for ( auto i = 0u; i < 100u; ++i ) { kitty::dynamic_truth_table func( 4u ); - kitty::create_random( func ); + kitty::create_random( func, 0xcafeaffe + i ); std::vector transformations; const auto repr = kitty::hybrid_exact_spectral_canonization( func, [&]( auto const& _transformations ) { @@ -70,9 +71,14 @@ TEST_CASE( "Synthesize from database for 4-input functions", "[equivalence_class std::generate( pis.begin(), pis.end(), [&]() { return xag.create_pi(); } ); const auto f = apply_spectral_transformations( xag, transformations, pis, [&]( xag_network& ntk, std::vector const& leaves ) { - return create_from_binary_index_list( ntk, db[repr]->begin(), leaves.begin() )[0u]; + xag_index_list il{*db[repr]}; + std::vector pos; + insert( ntk, std::begin( leaves ), std::begin( leaves ) + il.num_pis(), il, + [&]( xag_network::signal const& s ){ pos.emplace_back( s ); }); + return pos[0]; } ); xag.create_po( f ); + CHECK( simulate( xag, {static_cast( func.num_vars() )} )[0] == func ); } } diff --git a/test/io/index_list.cpp b/test/io/index_list.cpp index 209132e65..60dc9fc88 100644 --- a/test/io/index_list.cpp +++ b/test/io/index_list.cpp @@ -1,25 +1,14 @@ #include -#include -#include -#include - #include -#include #include -#include -#include -#include -#include -#include #include -#include -#include - -#include -#include +#include #include -#include + +#include +#include +#include using namespace mockturtle; @@ -28,13 +17,7 @@ static void check_minmc_xags() { for ( auto const& [cls, tt, repr, expr] : detail::minmc_xags[NumVars] ) { xag_network xag; - std::vector pis( NumVars ); - std::generate( pis.begin(), pis.end(), [&]() { return xag.create_pi(); }); - - for ( auto const& po : create_from_binary_index_list( xag, repr.begin(), pis.begin() ) ) - { - xag.create_po( po ); - } + decode( xag, xag_index_list{repr} ); const auto f = simulate>( xag )[0]; auto f_tt = f.construct(), f_expr = f.construct(); From 2f41e8a64234caee0c62844b79cc523f83c7b5bd Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 00:21:45 +0200 Subject: [PATCH 10/14] index-list: supporting gcc7. --- include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp | 1 + include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp b/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp index 9ff27459b..0dfcfdb72 100644 --- a/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp +++ b/include/mockturtle/algorithms/node_resynthesis/xag_minmc2.hpp @@ -150,6 +150,7 @@ class xag_minmc_resynthesis for ( auto const& [_, word, repr, expr] : detail::minmc_xags[i] ) { (void)_; + (void)expr; db_[i][word] = repr; st_.db_size += sizeof( word ) + sizeof( repr ) + sizeof( uint32_t ) * repr.size(); } diff --git a/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp b/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp index 6e358cd53..ccdca1c63 100644 --- a/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp +++ b/include/mockturtle/algorithms/node_resynthesis/xag_npn.hpp @@ -210,7 +210,7 @@ class xag_npn_resynthesis { stopwatch t( st.time_db ); - decode( _db, xag_index_list{std::vector( subgraphs, subgraphs + sizeof subgraphs / sizeof subgraphs[0] )} ); + decode( _db, xag_index_list{std::vector{subgraphs, subgraphs + sizeof subgraphs / sizeof subgraphs[0]}} ); const auto sim_res = simulate_nodes>( _db ); _db.foreach_node( [&]( auto n ) { From f3b40bfb36a10fc27cc5543253e6d9ba13743930 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 10:25:13 +0200 Subject: [PATCH 11/14] index_list: to_string. --- include/mockturtle/io/index_list.hpp | 224 ------------------ include/mockturtle/utils/index_list.hpp | 82 ++++++- test/algorithms/equivalence_classes.cpp | 1 - .../minmc_xags.cpp} | 4 +- test/utils/index_list.cpp | 4 +- 5 files changed, 81 insertions(+), 234 deletions(-) delete mode 100644 include/mockturtle/io/index_list.hpp rename test/{io/index_list.cpp => algorithms/minmc_xags.cpp} (91%) diff --git a/include/mockturtle/io/index_list.hpp b/include/mockturtle/io/index_list.hpp deleted file mode 100644 index 0f65bc961..000000000 --- a/include/mockturtle/io/index_list.hpp +++ /dev/null @@ -1,224 +0,0 @@ -/* mockturtle: C++ logic network library - * Copyright (C) 2018-2019 EPFL - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/*! - \file index_list.hpp - \brief Network representation as index lists - - \author Mathias Soeken -*/ - -#pragma once - -#include -#include -#include - -#include "../networks/aig.hpp" -#include "../networks/xag.hpp" -#include "../traits.hpp" - -#include - -namespace mockturtle -{ - -/*! \brief Creates AND and XOR gates from binary index list. - * - * The `begin` iterator points to the first index of an index list that has the - * following 32-bit unsigned integer elements. It starts with a signature whose - * partitioned into `| num_gates | num_pos | num_pis |`, where `num_gates` - * accounts for the most-significant 16 bits, `num_pos` accounts for 8 bits, and - * `num_pis` accounts for the least-significant 8 bits. Afterwards, gates are - * defined as literal indexes `(2 * i + c)`, where `i` is an index, with 0 - * indexing the constant 0, 1 to `num_pis` indexing the primary inputs, and all - * successive indexes for the gates. Gate literals come in pairs. If the first - * literal has a smaller value than the second one, an AND gate is created, - * otherwise, an XOR gate is created. Afterwards, all outputs are defined in - * terms of literals. The length of both the index list and the primary input - * list can be derived from the signature, and therefore, no end iterators need - * to be passed to this function. - * - * \param dest Network - * \param begin Start iterator to index list - * \param pi_begin Start iterator to primary inputs (in network) - * \return Returns a vector of signals created based on index list - * - * Example: The following index list creates (x1 AND x2) XOR (x3 AND x4): - * `{3 << 16 | 1 << 8 | 4, 2, 4, 6, 8, 12, 10, 14}` - */ -template -std::vector> create_from_binary_index_list( Ntk& dest, IndexIterator begin, LeavesIterator pi_begin ) -{ - static_assert( is_network_type_v, "Ntk is not a network type" ); - - static_assert( has_get_constant_v, "Ntk does not implement the get_constant method" ); - static_assert( has_create_and_v, "Ntk does not implement the create_and method" ); - static_assert( has_create_xor_v, "Ntk does not implement the create_xor method" ); - static_assert( has_create_not_v, "Ntk does not implement the create_not method" ); - - static_assert( std::is_same_v::value_type>, uint32_t>, "IndexIterator value_type must be uint32_t" ); - static_assert( std::is_same_v::value_type>, signal>, "LeavesIterator value_type must be Ntk signal type" ); - - const auto signature = *begin++; - const auto num_pis = signature & 0xff; - const auto num_pos = ( signature >> 8 ) & 0xff; - const auto num_gates = signature >> 16; - - // initialize gate-signal list - std::vector> fs; - fs.push_back( dest.get_constant( false ) ); - std::copy_n( pi_begin, num_pis, std::back_inserter( fs ) ); - - for ( auto i = 0u; i < num_gates; ++i ) - { - const auto signal1 = *begin++; - const auto signal2 = *begin++; - - const auto c1 = signal1 % 2 ? dest.create_not( fs[signal1 / 2] ) : fs[signal1 / 2]; - const auto c2 = signal2 % 2 ? dest.create_not( fs[signal2 / 2] ) : fs[signal2 / 2]; - - fs.push_back( signal1 > signal2 ? dest.create_xor( c1, c2 ) : dest.create_and( c1, c2 ) ); - } - - std::vector> pos( num_pos ); - for ( auto i = 0u; i < num_pos; ++i ) - { - const auto signal = *begin++; - pos[i] = signal % 2 ? dest.create_not( fs[signal / 2] ) : fs[signal / 2]; - } - - return pos; -} - -/*! \brief Creates AND and XOR gates from binary index list. - * - * An out-of-place variant for create_from_binary_index_list. - */ -template -Ntk create_from_binary_index_list( IndexIterator begin ) -{ - static_assert( is_network_type_v, "Ntk is not a network type" ); - static_assert( has_create_pi_v, "Ntk does not implement the create_pi method" ); - static_assert( has_create_po_v, "Ntk does not implement the create_po method" ); - - static_assert( std::is_same_v::value_type>, uint32_t>, "IndexIterator value_type must be uint32_t" ); - - Ntk ntk; - std::vector> pis( *begin & 0xff ); - std::generate( pis.begin(), pis.end(), [&]() { return ntk.create_pi(); } ); - for ( auto const& f : create_from_binary_index_list( ntk, begin, pis.begin() ) ) - { - ntk.create_po( f ); - } - return ntk; -} - -namespace detail -{ - -template -std::vector to_index_list( Ntk const& ntk ) -{ - static_assert( std::is_same_v || std::is_same_v, "Ntk must be XAG or AIG" ); - - std::vector index_list; - index_list.push_back( ( ntk.num_gates() << 16 ) | ( ntk.num_pos() << 8 ) | ntk.num_pis() ); - - ntk.foreach_pi( [&]( auto const& n, auto i ) { - if ( ntk.node_to_index( n ) != i + 1 ) { - fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", i + 1 ); - std::abort(); - } - }); - - ntk.foreach_gate( [&]( auto const& n, auto i ) { - if ( ntk.node_to_index( n ) != ntk.num_pis() + i + 1 ) - { - fmt::print( "[e] network is not in normalized index order (violated by node {})\n", ntk.node_to_index( n ) ); - std::abort(); - } - - ntk.foreach_fanin( n, [&]( auto const& f ) { - if ( ntk.node_to_index( ntk.get_node( f ) ) > ntk.node_to_index( n ) ) - { - fmt::print( "[e] node {} not in topological order\n", ntk.node_to_index( n ) ); - std::abort(); - } - index_list.push_back( 2 * ntk.node_to_index( ntk.get_node( f ) ) + ( ntk.is_complemented( f ) ? 1 : 0 ) ); - } ); - } ); - - ntk.foreach_po( [&]( auto const& f ) { - index_list.push_back( 2 * ntk.node_to_index( ntk.get_node( f ) ) + ( ntk.is_complemented( f ) ? 1 : 0 ) ); - }); - - return index_list; -} - -template -std::string to_index_list_string( Ntk const& ntk ) -{ - static_assert( std::is_same_v || std::is_same_v, "Ntk must be XAG or AIG" ); - - /* compute signature */ - auto s = fmt::format( "{{{} << 16 | {} << 8 | {}", ntk.num_gates(), ntk.num_pos(), ntk.num_pis() ); - - ntk.foreach_pi( [&]( auto const& n, auto i ) { - if ( ntk.node_to_index( n ) != i + 1 ) { - fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", i + 1 ); - std::abort(); - } - }); - - ntk.foreach_gate( [&]( auto const& n, auto i ) { - if ( ntk.node_to_index( n ) != ntk.num_pis() + i + 1 ) - { - fmt::print( "[e] network is not in normalized index order (violated by node {})\n", ntk.node_to_index( n ) ); - std::abort(); - } - - ntk.foreach_fanin( n, [&]( auto const& f ) { - if ( ntk.node_to_index( ntk.get_node( f ) ) > ntk.node_to_index( n ) ) - { - fmt::print( "[e] node {} not in topological order\n", ntk.node_to_index( n ) ); - std::abort(); - } - s += fmt::format( ", {}", 2 * ntk.node_to_index( ntk.get_node( f ) ) + ( ntk.is_complemented( f ) ? 1 : 0 ) ); - } ); - } ); - - ntk.foreach_po( [&]( auto const& f ) { - s += fmt::format( ", {}", 2 * ntk.node_to_index( ntk.get_node( f ) ) + ( ntk.is_complemented( f ) ? 1 : 0 ) ); - }); - - s += "}"; - - return s; -} - -} - -} /* namespace mockturtle */ diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index ccb4da209..5f5638329 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -26,7 +26,9 @@ /*! \file index_list.hpp \brief List of indices to represent small networks. + \author Heinz Riener + \author Mathias Soeken */ #pragma once @@ -303,6 +305,33 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic }); } +/*! \brief Converts an abc_index_list to a string + * + * \param indices An index list + * \return A string representation of the index list + */ +inline std::string to_string( abc_index_list const& indices ) +{ + std::string s; + s += "{"; + auto it = indices.raw().begin(); + while ( true ) + { + s += fmt::format( "{}", *it ); + it++; + if ( it != indices.raw().end() ) + { + s += ", "; + } + else + { + break; + } + } + s += "}"; + return s; +} + /*! \brief Index list for majority-inverter graphs. * * Small network consisting of majority gates and inverters @@ -504,12 +533,9 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic } indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1, uint32_t lit2 ){ - uint32_t const i0 = lit0 >> 1; - uint32_t const i1 = lit1 >> 1; - uint32_t const i2 = lit2 >> 1; - signal const s0 = ( lit0 % 2 ) ? !signals.at( i0 ) : signals.at( i0 ); - signal const s1 = ( lit1 % 2 ) ? !signals.at( i1 ) : signals.at( i1 ); - signal const s2 = ( lit2 % 2 ) ? !signals.at( i2 ) : signals.at( i2 ); + signal const s0 = ( lit0 % 2 ) ? !signals.at( lit0 >> 1 ) : signals.at( lit0 >> 1 ); + signal const s1 = ( lit1 % 2 ) ? !signals.at( lit1 >> 1 ) : signals.at( lit1 >> 1 ); + signal const s2 = ( lit2 % 2 ) ? !signals.at( lit2 >> 1 ) : signals.at( lit2 >> 1 ); signals.push_back( ntk.create_maj( s0, s1, s2 ) ); }); @@ -519,6 +545,28 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic }); } +/*! \brief Converts an mig_index_list to a string + * + * \param indices An index list + * \return A string representation of the index list + */ +inline std::string to_string( mig_index_list const& indices ) +{ + auto s = fmt::format( "{{{} | {} << 8 | {} << 16", indices.num_pis(), indices.num_pos(), indices.num_gates() ); + + indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1, uint32_t lit2 ){ + s += fmt::format( ", {}, {}, {}", lit0, lit1, lit2 ); + }); + + indices.foreach_po( [&]( uint32_t lit ) { + s += fmt::format( ", {}", lit ); + }); + + s += "}"; + + return s; +} + /*! \brief Index list for xor-and graphs. * * Small network represented as a list of literals. Supports XOR and @@ -766,6 +814,28 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indic }); } +/*! \brief Converts an xag_index_list to a string + * + * \param indices An index list + * \return A string representation of the index list + */ +inline std::string to_string( xag_index_list const& indices ) +{ + auto s = fmt::format( "{{{} | {} << 8 | {} << 16", indices.num_pis(), indices.num_pos(), indices.num_gates() ); + + indices.foreach_entry( [&]( uint32_t lit0, uint32_t lit1 ){ + s += fmt::format( ", {}, {}", lit0, lit1 ); + }); + + indices.foreach_po( [&]( uint32_t lit ) { + s += fmt::format( ", {}", lit ); + }); + + s += "}"; + + return s; +} + /*! \brief Generates a network from an index_list * * **Required network functions:** diff --git a/test/algorithms/equivalence_classes.cpp b/test/algorithms/equivalence_classes.cpp index 0690eeb2a..9f8d19d1e 100644 --- a/test/algorithms/equivalence_classes.cpp +++ b/test/algorithms/equivalence_classes.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/test/io/index_list.cpp b/test/algorithms/minmc_xags.cpp similarity index 91% rename from test/io/index_list.cpp rename to test/algorithms/minmc_xags.cpp index 60dc9fc88..ea5a82f2a 100644 --- a/test/io/index_list.cpp +++ b/test/algorithms/minmc_xags.cpp @@ -29,7 +29,7 @@ static void check_minmc_xags() } } -TEST_CASE( "create MC-optumum XAGs from binary index list", "[index_list]" ) +TEST_CASE( "create MC-optumum XAGs from xag_index_list", "[minmc_xags]" ) { check_minmc_xags<0>(); check_minmc_xags<1>(); @@ -56,7 +56,7 @@ static void check_repr_match() } } -TEST_CASE( "check representatives for database functions", "[index_list]" ) +TEST_CASE( "check representatives for database functions", "[minmc_xags]" ) { check_repr_match<0>(); check_repr_match<1>(); diff --git a/test/utils/index_list.cpp b/test/utils/index_list.cpp index f96485ee4..7ca01b9f4 100644 --- a/test/utils/index_list.cpp +++ b/test/utils/index_list.cpp @@ -43,6 +43,7 @@ TEST_CASE( "encode mig_network into mig_index_list", "[index_list]" ) CHECK( mig_il.num_gates() == 2u ); CHECK( mig_il.size() == 8u ); CHECK( mig_il.raw() == std::vector{4 | ( 1 << 8 ) | ( 2 << 16 ), 2, 4, 6, 4, 8, 10, 12} ); + CHECK( to_string( mig_il ) == "{4 | 1 << 8 | 2 << 16, 2, 4, 6, 4, 8, 10, 12}" ); } TEST_CASE( "decode abc_index_list into xag_network", "[index_list]" ) @@ -81,6 +82,7 @@ TEST_CASE( "encode xag_network into abc_index_list", "[index_list]" ) CHECK( xag_il.num_gates() == 3u ); CHECK( xag_il.size() == 18u ); CHECK( xag_il.raw() == std::vector{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14} ); + CHECK( to_string( xag_il ) == "{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}" ); } TEST_CASE( "decode xag_index_list into xag_network", "[index_list]" ) @@ -119,5 +121,5 @@ TEST_CASE( "encode xag_network into xag_index_list", "[index_list]" ) CHECK( xag_il.num_gates() == 3u ); CHECK( xag_il.size() == 8u ); CHECK( xag_il.raw() == std::vector{4 | ( 1 << 8 ) | ( 3 << 16 ), 2, 4, 6, 8, 12, 10, 14} ); + CHECK( to_string( xag_il ) == "{4 | 1 << 8 | 3 << 16, 2, 4, 6, 8, 12, 10, 14}" ); } - From 1e34db97d68e6dd969dc98577fc09884089d4aa0 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 10:28:49 +0200 Subject: [PATCH 12/14] changelog. --- docs/changelog.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index ce67dd471..6dbc7f6b0 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -39,8 +39,9 @@ v0.2 (not yet released) - Write networks to DIMACS files for CNF (`write_dimacs`) `#146 `_ - Read BLIF files using *lorina* (`blif_reader`) `#167 `_ - Write networks to BLIF files (`write_blif`) `#169 `_ `#184 `_ - - Create circuit from integer index list (`create_from_binary_index_list`) `#259 `_ - Write networks to AIGER files (`write_aiger`) `#379 `_ +* Utils + - Create circuit from integer index list (`encode`, `decode`, `insert`, `to_string`) `#385 `_ * Resynthesis functions: - Resynthesis function based on DSD decomposition (`dsd_resynthesis`) `#182 `_ - Resynthesis function based on Shannon decomposition (`shannon_resynthesis`) `#185 `_ From 2f8b7c745dd923086454489036647db00f36c56a Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 10:52:39 +0200 Subject: [PATCH 13/14] index_list. --- docs/changelog.rst | 2 +- include/mockturtle/utils/index_list.hpp | 17 ++++++++--------- test/utils/index_list.cpp | 6 +++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6dbc7f6b0..dc9d2ff5f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -41,7 +41,7 @@ v0.2 (not yet released) - Write networks to BLIF files (`write_blif`) `#169 `_ `#184 `_ - Write networks to AIGER files (`write_aiger`) `#379 `_ * Utils - - Create circuit from integer index list (`encode`, `decode`, `insert`, `to_string`) `#385 `_ + - Create circuit from integer index list (`encode`, `decode`, `insert`, `to_index_list_string`) `#385 `_ * Resynthesis functions: - Resynthesis function based on DSD decomposition (`dsd_resynthesis`) `#182 `_ - Resynthesis function based on Shannon decomposition (`shannon_resynthesis`) `#185 `_ diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 5f5638329..3415cb27f 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -207,10 +207,10 @@ void encode( abc_index_list& indices, Ntk const& ntk ) using node = typename Ntk::node; using signal = typename Ntk::signal; - ntk.foreach_pi( [&]( node const& n, uint64_t i ) { - if ( ntk.node_to_index( n ) != i + 1 ) + ntk.foreach_pi( [&]( node const& n, uint64_t index ) { + if ( ntk.node_to_index( n ) != index + 1 ) { - fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", i + 1 ); + fmt::print( "[e] network is not in normalized index order (violated by PI {})\n", index + 1 ); std::abort(); } }); @@ -310,14 +310,13 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic * \param indices An index list * \return A string representation of the index list */ -inline std::string to_string( abc_index_list const& indices ) +inline std::string to_index_list_string( abc_index_list const& indices ) { - std::string s; - s += "{"; + std::string s{"{"}; auto it = indices.raw().begin(); while ( true ) { - s += fmt::format( "{}", *it ); + s += std::to_string( *it ); it++; if ( it != indices.raw().end() ) { @@ -550,7 +549,7 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, mig_index_list const& indic * \param indices An index list * \return A string representation of the index list */ -inline std::string to_string( mig_index_list const& indices ) +inline std::string to_index_list_string( mig_index_list const& indices ) { auto s = fmt::format( "{{{} | {} << 8 | {} << 16", indices.num_pis(), indices.num_pos(), indices.num_gates() ); @@ -819,7 +818,7 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, xag_index_list const& indic * \param indices An index list * \return A string representation of the index list */ -inline std::string to_string( xag_index_list const& indices ) +inline std::string to_index_list_string( xag_index_list const& indices ) { auto s = fmt::format( "{{{} | {} << 8 | {} << 16", indices.num_pis(), indices.num_pos(), indices.num_gates() ); diff --git a/test/utils/index_list.cpp b/test/utils/index_list.cpp index 7ca01b9f4..a258de0c3 100644 --- a/test/utils/index_list.cpp +++ b/test/utils/index_list.cpp @@ -43,7 +43,7 @@ TEST_CASE( "encode mig_network into mig_index_list", "[index_list]" ) CHECK( mig_il.num_gates() == 2u ); CHECK( mig_il.size() == 8u ); CHECK( mig_il.raw() == std::vector{4 | ( 1 << 8 ) | ( 2 << 16 ), 2, 4, 6, 4, 8, 10, 12} ); - CHECK( to_string( mig_il ) == "{4 | 1 << 8 | 2 << 16, 2, 4, 6, 4, 8, 10, 12}" ); + CHECK( to_index_list_string( mig_il ) == "{4 | 1 << 8 | 2 << 16, 2, 4, 6, 4, 8, 10, 12}" ); } TEST_CASE( "decode abc_index_list into xag_network", "[index_list]" ) @@ -82,7 +82,7 @@ TEST_CASE( "encode xag_network into abc_index_list", "[index_list]" ) CHECK( xag_il.num_gates() == 3u ); CHECK( xag_il.size() == 18u ); CHECK( xag_il.raw() == std::vector{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14} ); - CHECK( to_string( xag_il ) == "{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}" ); + CHECK( to_index_list_string( xag_il ) == "{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 6, 8, 12, 10, 14, 14}" ); } TEST_CASE( "decode xag_index_list into xag_network", "[index_list]" ) @@ -121,5 +121,5 @@ TEST_CASE( "encode xag_network into xag_index_list", "[index_list]" ) CHECK( xag_il.num_gates() == 3u ); CHECK( xag_il.size() == 8u ); CHECK( xag_il.raw() == std::vector{4 | ( 1 << 8 ) | ( 3 << 16 ), 2, 4, 6, 8, 12, 10, 14} ); - CHECK( to_string( xag_il ) == "{4 | 1 << 8 | 3 << 16, 2, 4, 6, 8, 12, 10, 14}" ); + CHECK( to_index_list_string( xag_il ) == "{4 | 1 << 8 | 3 << 16, 2, 4, 6, 8, 12, 10, 14}" ); } From d404245f1faa40990ff911ac1fd5435466bb9688 Mon Sep 17 00:00:00 2001 From: Heinz Riener Date: Wed, 14 Oct 2020 11:14:22 +0200 Subject: [PATCH 14/14] index_list. --- include/mockturtle/utils/index_list.hpp | 29 +++++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/include/mockturtle/utils/index_list.hpp b/include/mockturtle/utils/index_list.hpp index 3415cb27f..48e558f8f 100644 --- a/include/mockturtle/utils/index_list.hpp +++ b/include/mockturtle/utils/index_list.hpp @@ -60,9 +60,17 @@ struct abc_index_list public: explicit abc_index_list( uint32_t num_pis = 0 ) - : _num_pis( num_pis ) - , values( /* add constant */{ 0u, 1u } ) - {} + { + /* add constants */ + values.push_back( 0u ); + values.push_back( 1u ); + + /* add inputs */ + if ( num_pis > 0 ) + { + add_inputs( num_pis ); + } + } explicit abc_index_list( std::vector const& values ) : values( std::begin( values ), std::end( values ) ) @@ -80,7 +88,6 @@ struct abc_index_list break; } } - for ( ; ( i+1 ) < values.size(); i+=2 ) { assert( !( values.at( i ) == 0 && values.at( i + 1 ) == 0 ) ); @@ -312,20 +319,18 @@ void insert( Ntk& ntk, BeginIter begin, EndIter end, abc_index_list const& indic */ inline std::string to_index_list_string( abc_index_list const& indices ) { + auto const raw = indices.raw(); + std::string s{"{"}; - auto it = indices.raw().begin(); - while ( true ) + auto it = std::begin( raw ); + while ( it != std::end( raw ) ) { s += std::to_string( *it ); - it++; - if ( it != indices.raw().end() ) + ++it; + if ( it != std::end( raw ) ) { s += ", "; } - else - { - break; - } } s += "}"; return s;