Skip to content

Commit

Permalink
partial simulator (lsils#337)
Browse files Browse the repository at this point in the history
* minor bug fixes

* partial simulator

Currently only supports AIG

* Update include/mockturtle/algorithms/simulation.hpp

Co-Authored-By: Mathias Soeken <[email protected]>

* Update include/mockturtle/algorithms/simulation.hpp

Co-Authored-By: Mathias Soeken <[email protected]>

* Update include/mockturtle/algorithms/simulation.hpp

Co-Authored-By: Mathias Soeken <[email protected]>

Co-authored-by: Mathias Soeken <[email protected]>
  • Loading branch information
lee30sonia and msoeken authored Apr 22, 2020
1 parent 34ee82f commit 35d1f7e
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 4 deletions.
153 changes: 153 additions & 0 deletions include/mockturtle/algorithms/simulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@

#include <cstdint>
#include <vector>
#include <fstream>

#include "../traits.hpp"
#include "../utils/node_map.hpp"

#include <kitty/constructors.hpp>
#include <kitty/dynamic_truth_table.hpp>
#include <kitty/operators.hpp>
#include <kitty/partial_truth_table.hpp>
#include <kitty/print.hpp>
#include <kitty/static_truth_table.hpp>

namespace mockturtle
Expand Down Expand Up @@ -158,6 +161,90 @@ class default_simulator<kitty::static_truth_table<NumVars>>
}
};

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<kitty::partial_truth_table> 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<bool>& 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<kitty::partial_truth_table> patterns;
};

/*! \brief Simulates a network with a generic simulator.
*
* This is a generic simulation algorithm that can simulate arbitrary values.
Expand Down Expand Up @@ -306,6 +393,72 @@ void simulate_nodes( Ntk const& ntk, unordered_node_map<SimulationType, Ntk>& no
} );
}

namespace detail
{

/* helper function to fix the non-topological order problem */
template<class Ntk>
void simulate_fanin_cone( Ntk const& ntk, typename Ntk::node const& n, unordered_node_map<kitty::partial_truth_table, Ntk>& node_to_value, partial_simulator const& sim, uint32_t& num_bits )
{
std::vector<kitty::partial_truth_table> 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<class Ntk>
void simulate_nodes( Ntk const& ntk, unordered_node_map<kitty::partial_truth_table, Ntk>& 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>, "Ntk is not a network type" );
static_assert( has_get_constant_v<Ntk>, "Ntk does not implement the get_constant method" );
static_assert( has_constant_value_v<Ntk>, "Ntk does not implement the constant_value method" );
static_assert( has_get_node_v<Ntk>, "Ntk does not implement the get_node method" );
static_assert( has_foreach_pi_v<Ntk>, "Ntk does not implement the foreach_pi method" );
static_assert( has_foreach_gate_v<Ntk>, "Ntk does not implement the foreach_gate method" );
static_assert( has_foreach_fanin_v<Ntk>, "Ntk does not implement the foreach_fanin method" );
static_assert( has_fanin_size_v<Ntk>, "Ntk does not implement the fanin_size method" );
static_assert( has_num_pos_v<Ntk>, "Ntk does not implement the num_pos method" );
static_assert( has_compute_v<Ntk, kitty::partial_truth_table>, "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.
Expand Down
28 changes: 28 additions & 0 deletions include/mockturtle/networks/aig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <string>

#include <kitty/dynamic_truth_table.hpp>
#include <kitty/partial_truth_table.hpp>
#include <kitty/operators.hpp>

#include "../traits.hpp"
Expand Down Expand Up @@ -1022,6 +1023,33 @@ class aig_network

return ( c1.weight ? ~tt1 : tt1 ) & ( c2.weight ? ~tt2 : tt2 );
}

template<typename Iterator>
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
Expand Down
9 changes: 5 additions & 4 deletions lib/kitty/kitty/partial_truth_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions test/algorithms/simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<kitty::partial_truth_table> 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<kitty::partial_truth_table, aig_network> node_to_value( aig );
simulate_nodes<kitty::partial_truth_table>( 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<kitty::partial_truth_table>( 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 */
}

0 comments on commit 35d1f7e

Please sign in to comment.