From 35d1f7e6a895b0dcc4e1bb7a339f12e192fd978a Mon Sep 17 00:00:00 2001 From: "Siang-Yun (Sonia) Lee" Date: Wed, 22 Apr 2020 20:44:07 +0200 Subject: [PATCH] partial simulator (#337) * minor bug fixes * partial simulator Currently only supports AIG * Update include/mockturtle/algorithms/simulation.hpp Co-Authored-By: Mathias Soeken * Update include/mockturtle/algorithms/simulation.hpp Co-Authored-By: Mathias Soeken * Update include/mockturtle/algorithms/simulation.hpp Co-Authored-By: Mathias Soeken Co-authored-by: Mathias Soeken --- include/mockturtle/algorithms/simulation.hpp | 153 +++++++++++++++++++ include/mockturtle/networks/aig.hpp | 28 ++++ lib/kitty/kitty/partial_truth_table.hpp | 9 +- test/algorithms/simulation.cpp | 35 +++++ 4 files changed, 221 insertions(+), 4 deletions(-) diff --git a/include/mockturtle/algorithms/simulation.hpp b/include/mockturtle/algorithms/simulation.hpp index 79cf58fa8..98aa7f72b 100644 --- a/include/mockturtle/algorithms/simulation.hpp +++ b/include/mockturtle/algorithms/simulation.hpp @@ -34,6 +34,7 @@ #include #include +#include #include "../traits.hpp" #include "../utils/node_map.hpp" @@ -41,6 +42,8 @@ #include #include #include +#include +#include #include namespace mockturtle @@ -158,6 +161,90 @@ class default_simulator> } }; +class partial_simulator +{ +public: + partial_simulator() = delete; + partial_simulator( unsigned num_pis, unsigned num_pattern, std::default_random_engine::result_type seed = 0 ) + { + assert( num_pis > 0u ); + + for ( auto i = 0u; i < num_pis; ++i ) + { + patterns.emplace_back( num_pattern ); + kitty::create_random( patterns.back(), seed + i ); + } + } + + /* copy constructor */ + partial_simulator( partial_simulator const& sim ) + { + patterns = sim.patterns; + } + + partial_simulator( std::vector const& pats ) + { + patterns = pats; + } + + partial_simulator( const std::string& filename, uint32_t length = 0u ) + { + std::ifstream in( filename, std::ifstream::in ); + std::string line; + + while ( getline( in, line ) ) + { + patterns.emplace_back( line.length() * 4 ); + kitty::create_from_hex_string( patterns.back(), line ); + if ( length != 0u ) + { + patterns.back().resize( length ); + } + } + + in.close(); + } + + kitty::partial_truth_table compute_constant( bool value ) const + { + kitty::partial_truth_table zero( patterns.at( 0 ).num_bits() ); + return value ? ~zero : zero; + } + + kitty::partial_truth_table compute_pi( uint32_t index ) const + { + return patterns.at( index ); + } + + kitty::partial_truth_table compute_not( kitty::partial_truth_table const& value ) const + { + return ~value; + } + + void add_pattern( std::vector& pattern ) + { + assert( pattern.size() == patterns.size() ); + + for ( auto i = 0u; i < pattern.size(); ++i ) + { + patterns.at( i ).add_bit( pattern.at( i ) ); + } + } + + void write_patterns( const std::string& filename ) + { + std::ofstream out( filename, std::ofstream::out ); + for ( auto i = 0u; i < patterns.size(); ++i ) + { + out << kitty::to_hex( patterns.at( i ) ) << "\n"; + } + out.close(); + } + +private: + std::vector patterns; +}; + /*! \brief Simulates a network with a generic simulator. * * This is a generic simulation algorithm that can simulate arbitrary values. @@ -306,6 +393,72 @@ void simulate_nodes( Ntk const& ntk, unordered_node_map& no } ); } +namespace detail +{ + +/* helper function to fix the non-topological order problem */ +template +void simulate_fanin_cone( Ntk const& ntk, typename Ntk::node const& n, unordered_node_map& node_to_value, partial_simulator const& sim, uint32_t& num_bits ) +{ + std::vector fanin_values( ntk.fanin_size( n ) ); + ntk.foreach_fanin( n, [&]( auto const& f, auto i ) { + if ( !node_to_value.has( ntk.get_node( f ) ) || node_to_value[ntk.get_node( f )].num_bits() != num_bits ) + simulate_fanin_cone( ntk, ntk.get_node( f ), node_to_value, sim, num_bits ); + fanin_values[i] = node_to_value[ntk.get_node( f )]; + } ); + ntk.compute( n, node_to_value[n], fanin_values.begin(), fanin_values.end() ); +} + +} // namespace detail + +/* specialization for partial_truth_table */ +template +void simulate_nodes( Ntk const& ntk, unordered_node_map& node_to_value, partial_simulator const& sim ) +{ + /* TODO: The partial_truth_table specialized ntk.compute is currently only implemented in AIG. */ + 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_constant_value_v, "Ntk does not implement the constant_value method" ); + static_assert( has_get_node_v, "Ntk does not implement the get_node method" ); + static_assert( has_foreach_pi_v, "Ntk does not implement the foreach_pi method" ); + static_assert( has_foreach_gate_v, "Ntk does not implement the foreach_gate method" ); + static_assert( has_foreach_fanin_v, "Ntk does not implement the foreach_fanin method" ); + static_assert( has_fanin_size_v, "Ntk does not implement the fanin_size method" ); + static_assert( has_num_pos_v, "Ntk does not implement the num_pos method" ); + static_assert( has_compute_v, "Ntk does not implement the compute method for kitty::partial_truth_table" ); + + auto num_bits = sim.compute_constant( false ).num_bits(); + + /* constants */ + if ( !node_to_value.has( ntk.get_node( ntk.get_constant( false ) ) ) || node_to_value[ntk.get_node( ntk.get_constant( false ) )].num_bits() != num_bits ) + { + node_to_value[ntk.get_node( ntk.get_constant( false ) )] = sim.compute_constant( ntk.constant_value( ntk.get_node( ntk.get_constant( false ) ) ) ); + } + if ( ntk.get_node( ntk.get_constant( false ) ) != ntk.get_node( ntk.get_constant( true ) ) ) + { + if ( !node_to_value.has( ntk.get_node( ntk.get_constant( true ) ) ) || node_to_value[ntk.get_node( ntk.get_constant( true ) )].num_bits() != num_bits ) + { + node_to_value[ntk.get_node( ntk.get_constant( true ) )] = sim.compute_constant( ntk.constant_value( ntk.get_node( ntk.get_constant( true ) ) ) ); + } + } + + /* pis */ + ntk.foreach_pi( [&]( auto const& n, auto i ) { + if ( !node_to_value.has( n ) || node_to_value[n].num_bits() != num_bits ) + { + node_to_value[n] = sim.compute_pi( i ); + } + } ); + + /* gates */ + ntk.foreach_gate( [&]( auto const& n ) { + if ( !node_to_value.has( n ) || node_to_value[n].num_bits() != num_bits ) + { + detail::simulate_fanin_cone( ntk, n, node_to_value, sim, num_bits ); + } + } ); +} + /*! \brief Simulates a network with a generic simulator. * * This is a generic simulation algorithm that can simulate arbitrary values. diff --git a/include/mockturtle/networks/aig.hpp b/include/mockturtle/networks/aig.hpp index 289e46abe..3bdc43c2b 100644 --- a/include/mockturtle/networks/aig.hpp +++ b/include/mockturtle/networks/aig.hpp @@ -39,6 +39,7 @@ #include #include +#include #include #include "../traits.hpp" @@ -1022,6 +1023,33 @@ class aig_network return ( c1.weight ? ~tt1 : tt1 ) & ( c2.weight ? ~tt2 : tt2 ); } + + template + void compute( node const& n, kitty::partial_truth_table& result, Iterator begin, Iterator end ) const + { + (void)end; + /* TODO: assert type of *begin is partial_truth_table */ + + assert( n != 0 && !is_ci( n ) ); + + auto const& c1 = _storage->nodes[n].children[0]; + auto const& c2 = _storage->nodes[n].children[1]; + + auto tt1 = *begin++; + auto tt2 = *begin++; + + assert( tt1.num_bits() == tt2.num_bits() ); + assert( tt1.num_bits() >= result.num_bits() ); + if ( result.num_bits() == 0 ) + { + result = ( c1.weight ? ~tt1 : tt1 ) & ( c2.weight ? ~tt2 : tt2 ); + } + else + { + result.resize( tt1.num_bits() ); + result._bits.back() = ( c1.weight ? ~(tt1._bits.back()) : tt1._bits.back() ) & ( c2.weight ? ~(tt2._bits.back()) : tt2._bits.back() ); + } + } #pragma endregion #pragma region Custom node values diff --git a/lib/kitty/kitty/partial_truth_table.hpp b/lib/kitty/kitty/partial_truth_table.hpp index d5dc78f15..b6acf55eb 100644 --- a/lib/kitty/kitty/partial_truth_table.hpp +++ b/lib/kitty/kitty/partial_truth_table.hpp @@ -155,10 +155,7 @@ struct partial_truth_table _num_bits = num_bits; unsigned needed_blocks = num_bits ? ( ( ( num_bits - 1 ) >> 6 ) + 1 ) : 0; - if ( needed_blocks > _bits.size() ) - { - _bits.resize( needed_blocks, 0u ); - } + _bits.resize( needed_blocks, 0u ); mask_bits(); } @@ -187,6 +184,10 @@ struct partial_truth_table if ( ( _num_bits % 64 ) + num_bits <= 64 ) /* no need for a new block */ { + if ( _bits.size() == 0u ) + { + _bits.emplace_back( 0u ); + } _bits.back() |= bits << ( _num_bits % 64 ); } else diff --git a/test/algorithms/simulation.cpp b/test/algorithms/simulation.cpp index d2c2750a8..6aa8a9c55 100644 --- a/test/algorithms/simulation.cpp +++ b/test/algorithms/simulation.cpp @@ -90,3 +90,38 @@ TEST_CASE( "Simulate XOR AIG circuit with pre-defined values", "[simulation]" ) CHECK( ( aig.is_complemented( f3 ) ? ~node_to_value[f3] : node_to_value[f3] )._bits[0] == 0x3 ); CHECK( ( aig.is_complemented( f4 ) ? ~node_to_value[f4] : node_to_value[f4] )._bits[0] == 0xe ); } + +TEST_CASE( "Partial simulator", "[simulation]" ) +{ + 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 ); + + std::vector pats( 2 ); + pats[0].add_bits( 0x0a, 5 ); /* a = 01010 */ + pats[1].add_bits( 0x13, 5 ); /* b = 10011 */ + partial_simulator sim( pats ); + + unordered_node_map node_to_value( aig ); + simulate_nodes( aig, node_to_value, sim ); + + CHECK( ( aig.is_complemented( f4 ) ? ~node_to_value[f4] : node_to_value[f4] )._bits[0] == 0x19 ); /* f4 = 11001 */ + + node_to_value.reset(); + + /* set node f1 to false, such that function f1 becomes true */ + node_to_value[ aig.get_node( f1 ) ] = kitty::partial_truth_table( 5 ); + + /* re-simulated with the fixed value for f1 */ + simulate_nodes( aig, node_to_value, sim ); + CHECK( ( aig.is_complemented( f1 ) ? ~node_to_value[f1] : node_to_value[f1] )._bits[0] == 0x1f ); /* f1 = 11111 */ + CHECK( ( aig.is_complemented( f2 ) ? ~node_to_value[f2] : node_to_value[f2] )._bits[0] == 0x15 ); /* f2 = 10101 */ + CHECK( ( aig.is_complemented( f3 ) ? ~node_to_value[f3] : node_to_value[f3] )._bits[0] == 0x0c ); /* f3 = 01100 */ + CHECK( ( aig.is_complemented( f4 ) ? ~node_to_value[f4] : node_to_value[f4] )._bits[0] == 0x1b ); /* f4 = 11011 */ +}