Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 17 additions & 78 deletions include/mockturtle/io/aiger_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,72 +40,6 @@
namespace mockturtle
{

template<typename Ntk, typename StorageContainerMap = std::unordered_map<signal<Ntk>, std::vector<std::string>>, typename StorageContainerReverseMap = std::unordered_map<std::string, signal<Ntk>>>
class NameMap
{
public:
using signal = typename Ntk::signal;

public:
NameMap() = default;

void insert( signal const& s, std::string const& name )
{
/* update direct map */
auto const it = _names.find( s );
if ( it == _names.end() )
{
_names[s] = {name};
}
else
{
it->second.push_back( name );
}

/* update reverse map */
auto const rev_it = _rev_names.find( name );
if ( rev_it != _rev_names.end() )
{
std::cout << "[w] signal name `" << name << "` is used twice" << std::endl;
}
_rev_names.insert( std::make_pair( name, s ) );
}

std::vector<std::string> operator[]( signal const& s )
{
return _names[s];
}

std::vector<std::string> operator[]( signal const& s ) const
{
return _names.at( s );
}

std::vector<std::string> get_name( signal const& s ) const
{
return _names.at( s );
}

bool has_name( signal const& s, std::string const& name ) const
{
auto const it = _names.find( s );
if ( it == _names.end() )
{
return false;
}
return ( std::find( it->second.begin(), it->second.end(), name ) != it->second.end() );
}

StorageContainerReverseMap get_name_to_signal_mapping() const
{
return _rev_names;
}

protected:
StorageContainerMap _names;
StorageContainerReverseMap _rev_names;
}; // NameMap

/*! \brief Lorina reader callback for Aiger files.
*
* **Required network functions:**
Expand Down Expand Up @@ -136,7 +70,7 @@ template<typename Ntk>
class aiger_reader : public lorina::aiger_reader
{
public:
explicit aiger_reader( Ntk& ntk, NameMap<Ntk>* names = nullptr ) : _ntk( ntk ), _names( names )
explicit aiger_reader( Ntk& ntk ) : _ntk( ntk )
{
static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
static_assert( has_create_pi_v<Ntk>, "Ntk does not implement the create_pi function" );
Expand All @@ -148,6 +82,7 @@ class aiger_reader : public lorina::aiger_reader

~aiger_reader()
{
uint32_t output_id{0};
for ( auto out : outputs )
{
auto const lit = std::get<0>( out );
Expand All @@ -156,8 +91,10 @@ class aiger_reader : public lorina::aiger_reader
{
signal = _ntk.create_not( signal );
}
if ( _names )
_names->insert( signal, std::get<1>( out ) );
if constexpr ( has_set_output_name_v<Ntk> )
{
_ntk.set_output_name( output_id++, std::get<1>( out ) );
}
_ntk.create_po( signal );
}

Expand All @@ -174,8 +111,11 @@ class aiger_reader : public lorina::aiger_reader
signal = _ntk.create_not( signal );
}

if ( _names )
_names->insert( signal, std::get<2>( latch ) + "_next" );
if constexpr ( has_set_name_v<Ntk> )
{
_ntk.set_name( signal, std::get<2>( latch ) + "_next" );
}

_ntk.create_ri( signal, reset );
}
}
Expand Down Expand Up @@ -212,9 +152,9 @@ class aiger_reader : public lorina::aiger_reader

void on_input_name( unsigned index, const std::string& name ) const override
{
if ( _names )
if constexpr ( has_set_name_v<Ntk> )
{
_names->insert( signals[1 + index], name );
_ntk.set_name( signals[1 + index], name );
}
}

Expand All @@ -227,9 +167,9 @@ class aiger_reader : public lorina::aiger_reader
{
if constexpr ( has_create_ri_v<Ntk> && has_create_ro_v<Ntk> )
{
if ( _names )
if constexpr( has_set_name_v<Ntk> )
{
_names->insert( signals[1 + _num_inputs + index], name );
_ntk.set_name( signals[1 + _num_inputs + index], name );
}
std::get<2>( latches[index] ) = name;
}
Expand Down Expand Up @@ -275,11 +215,10 @@ class aiger_reader : public lorina::aiger_reader
private:
Ntk& _ntk;

mutable uint32_t _num_inputs = 0;
mutable uint32_t _num_inputs{0};
mutable std::vector<std::tuple<unsigned, std::string>> outputs;
mutable std::vector<typename Ntk::signal> signals;
mutable std::vector<std::tuple<unsigned, int8_t, std::string>> latches;
mutable NameMap<Ntk>* _names;
};

} /* namespace mockturtle */
} /* namespace mockturtle */
82 changes: 38 additions & 44 deletions test/io/aiger_reader.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
#include <catch.hpp>

#include <sstream>
#include <string>

#include <mockturtle/io/aiger_reader.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/views/names_view.hpp>

#include <lorina/aiger.hpp>

#include <sstream>
#include <string>

using namespace mockturtle;

TEST_CASE( "read and write names", "[aiger_reader]" )
{
aig_network aig;
names_view<aig_network> named_aig{aig};

std::string file{"aag 7 2 1 2 4\n"
"2\n"
Expand All @@ -31,28 +33,21 @@ TEST_CASE( "read and write names", "[aiger_reader]" )
"o1 y1\n"};

std::istringstream in( file );
auto const result = lorina::read_ascii_aiger( in, aiger_reader( aig ) );
auto const result = lorina::read_ascii_aiger( in, aiger_reader( named_aig ) );
CHECK( result == lorina::return_code::success );

NameMap<aig_network,std::map<aig_network::signal,std::vector<std::string>>> names;
names.insert( aig.make_signal( aig.pi_at( 0 ) ), "x0" );
names.insert( aig.make_signal( aig.pi_at( 1 ) ), "x1" );
names.insert( aig.make_signal( aig.ro_at( 0 ) ), "s0" );
names.insert( aig.ri_at( 0 ), "s0_next" );
names.insert( aig.po_at( 0 ), "y0" );
names.insert( aig.po_at( 1 ), "y1" );

CHECK( names.has_name( aig.make_signal( aig.pi_at( 0 ) ), "x0" ) );
CHECK( names.has_name( aig.make_signal( aig.pi_at( 1 ) ), "x1" ) );
CHECK( names.has_name( aig.po_at( 0 ), "y0" ) );
CHECK( names.has_name( aig.po_at( 1 ), "y1" ) );
CHECK( names.has_name( aig.make_signal( aig.ro_at( 0 ) ), "s0" ) );
CHECK( names.has_name( aig.ri_at( 0 ), "s0_next" ) );
CHECK( named_aig.get_name( aig.make_signal( aig.pi_at( 0 ) ) ) == "x0" );
CHECK( named_aig.get_name( aig.make_signal( aig.pi_at( 1 ) ) ) == "x1" );
CHECK( named_aig.get_name( aig.make_signal( aig.ro_at( 0 ) ) ) == "s0" );
CHECK( named_aig.get_name( aig.ri_at( 0 ) ) == "s0_next" );
CHECK( named_aig.get_output_name( 0 ) == "y0" );
CHECK( named_aig.get_output_name( 1 ) == "y1" );
}

TEST_CASE( "read an ASCII Aiger file into an AIG network and store input-output names", "[aiger_reader]" )
{
aig_network aig;
names_view<aig_network> named_aig{aig};

std::string file{"aag 6 2 0 1 4\n"
"2\n"
Expand All @@ -66,23 +61,23 @@ TEST_CASE( "read an ASCII Aiger file into an AIG network and store input-output
"i1 bar\n"
"o0 foobar\n"};

NameMap<aig_network> names;
std::istringstream in( file );
auto const result = lorina::read_ascii_aiger( in, aiger_reader( aig, &names ) );
auto const result = lorina::read_ascii_aiger( in, aiger_reader( named_aig ) );
CHECK( result == lorina::return_code::success );
CHECK( aig.size() == 7 );
CHECK( aig.num_pis() == 2 );
CHECK( aig.num_pos() == 1 );
CHECK( aig.num_gates() == 4 );

CHECK( names.has_name( aig.make_signal( aig.pi_at( 0 ) ), "foo" ) );
CHECK( names.has_name( aig.make_signal( aig.pi_at( 1 ) ), "bar" ) );
CHECK( names.has_name( aig.po_at( 0 ), "foobar" ) );
CHECK( named_aig.size() == 7 );
CHECK( named_aig.num_pis() == 2 );
CHECK( named_aig.num_pos() == 1 );
CHECK( named_aig.num_gates() == 4 );

CHECK( named_aig.get_name( aig.make_signal( aig.pi_at( 0 ) ) ) == "foo" );
CHECK( named_aig.get_name( aig.make_signal( aig.pi_at( 1 ) ) ) == "bar" );
CHECK( named_aig.get_output_name( 0 ) == "foobar" );
}

TEST_CASE( "read a sequential ASCII Aiger file into an AIG network", "[aiger_reader]" )
{
aig_network aig;
names_view<aig_network> named_aig{aig};

std::string file{"aag 7 2 1 2 4\n"
"2\n"
Expand All @@ -100,23 +95,22 @@ TEST_CASE( "read a sequential ASCII Aiger file into an AIG network", "[aiger_rea
"o0 foobar\n"
"o1 barbar\n"};

NameMap<aig_network> names;
lorina::diagnostic_engine diag;
std::istringstream in( file );
auto const result = lorina::read_ascii_aiger( in, aiger_reader( aig, &names ), &diag );
auto const result = lorina::read_ascii_aiger( in, aiger_reader( named_aig ), &diag );
CHECK( result == lorina::return_code::success );
CHECK( aig.size() == 8 );
CHECK( aig.num_cis() == 3 );
CHECK( aig.num_cos() == 3 );
CHECK( aig.num_pis() == 2 );
CHECK( aig.num_pos() == 2 );
CHECK( aig.num_gates() == 4 );
CHECK( aig.num_registers() == 1 );

CHECK( names.has_name( aig.make_signal( aig.pi_at( 0 ) ), "foo" ) );
CHECK( names.has_name( aig.make_signal( aig.pi_at( 1 ) ), "bar" ) );
CHECK( names.has_name( aig.make_signal( aig.ro_at( 0 ) ), "barfoo" ) );
CHECK( names.has_name( aig.ri_at( 0 ), "barfoo_next" ) );
CHECK( names.has_name( aig.po_at( 0 ), "foobar" ) );
CHECK( names.has_name( aig.po_at( 1 ), "barbar" ) );
CHECK( named_aig.size() == 8 );
CHECK( named_aig.num_cis() == 3 );
CHECK( named_aig.num_cos() == 3 );
CHECK( named_aig.num_pis() == 2 );
CHECK( named_aig.num_pos() == 2 );
CHECK( named_aig.num_gates() == 4 );
CHECK( named_aig.num_registers() == 1 );

CHECK( named_aig.get_name( aig.make_signal( aig.pi_at( 0 ) ) ) == "foo" );
CHECK( named_aig.get_name( aig.make_signal( aig.pi_at( 1 ) ) ) == "bar" );
CHECK( named_aig.get_name( aig.make_signal( aig.ro_at( 0 ) ) ) == "barfoo" );
CHECK( named_aig.get_name( aig.ri_at( 0 ) ) == "barfoo_next" );
CHECK( named_aig.get_output_name( 0 ) == "foobar" );
CHECK( named_aig.get_output_name( 1 ) == "barbar" );
}