Skip to content

Commit

Permalink
Additions to cut enumeration and cut rewriting (lsils#135)
Browse files Browse the repository at this point in the history
* Wrong return value in interface.

* Fix comments.

* Cut enumeration fixes.

* Cut rewriting fixes.

* Make XAG NPN work for non-complementable signals.

* Make XAG NPN more general.

* Fix cut rewriting.

* Cut enumeration for single-input gates.

* More fine-grained cut rewriting.
  • Loading branch information
msoeken authored Mar 8, 2019
1 parent 6f8fdcc commit a259f7d
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 14 deletions.
25 changes: 20 additions & 5 deletions include/mockturtle/algorithms/cut_enumeration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ class cut_enumeration_impl
const auto fanin = cut_sizes.size();
lcuts[fanin] = &cuts.cuts( index );

auto& rcuts = *lcuts[fanin == 1 ? 0 : fanin];
auto& rcuts = *lcuts[fanin];

if ( fanin > 1 )
{
Expand Down Expand Up @@ -487,16 +487,31 @@ class cut_enumeration_impl
return true;
} );

/* limit the maximum number of cuts */
rcuts.limit( ps.cut_limit - 1 );
} else { /* fanin == 1 */
rcuts.clear();

for ( auto const& cut : *lcuts[0] ) {
cut_t new_cut = *cut;

if constexpr ( ComputeTruth )
{
new_cut->func_id = compute_truth_table( index, {cut}, new_cut );
}

cut_enumeration_update_cut<CutData>::apply( new_cut, cuts, ntk, ntk.index_to_node( index ) );

rcuts.insert( new_cut );
}

/* limit the maximum number of cuts */
rcuts.limit( ps.cut_limit - 1 );
}

cuts._total_cuts += static_cast<uint32_t>( rcuts.size() );

if ( fanin == 1 || rcuts.size() > 1 || ( *rcuts.begin() )->size() > 1 )
{
cuts.add_unit_cut( index );
}
cuts.add_unit_cut( index );
}

private:
Expand Down
22 changes: 17 additions & 5 deletions include/mockturtle/algorithms/cut_rewriting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <optional>
#include <set>
#include <vector>

Expand Down Expand Up @@ -84,6 +85,12 @@ struct cut_rewriting_params
greedy
} candidate_selection_strategy = minimize_weight;

/*! \brief Minimum candidate cut size */
uint32_t min_cand_cut_size{3u};

/*! \brief Minimum candidate cut size override (in conflict graph) */
std::optional<uint32_t> min_cand_cut_size_override{};

/*! \brief Show progress. */
bool progress{false};

Expand Down Expand Up @@ -269,7 +276,7 @@ struct cut_enumeration_cut_rewriting_cut
};

template<typename Ntk, bool ComputeTruth>
std::tuple<graph, std::vector<std::pair<node<Ntk>, uint32_t>>> network_cuts_graph( Ntk const& ntk, network_cuts<Ntk, ComputeTruth, cut_enumeration_cut_rewriting_cut> const& cuts, bool allow_zero_gain )
std::tuple<graph, std::vector<std::pair<node<Ntk>, uint32_t>>> network_cuts_graph( Ntk const& ntk, network_cuts<Ntk, ComputeTruth, cut_enumeration_cut_rewriting_cut> const& cuts, cut_rewriting_params const& ps )
{
static_assert( is_network_type_v<Ntk>, "Ntk is not a network type" );
static_assert( has_size_v<Ntk>, "Ntk does not implement the size method" );
Expand Down Expand Up @@ -297,10 +304,15 @@ std::tuple<graph, std::vector<std::pair<node<Ntk>, uint32_t>>> network_cuts_grap
auto cctr{0u};
for ( auto const& cut : set )
{
if ( cut->size() <= 2 )
if ( ps.min_cand_cut_size_override )
{
if ( cut->size() < *ps.min_cand_cut_size_override )
continue;
}
else if ( cut->size() < ps.min_cand_cut_size )
continue;

if ( ( *cut )->data.gain < ( allow_zero_gain ? 0 : 1 ) )
if ( ( *cut )->data.gain < ( ps.allow_zero_gain ? 0 : 1 ) )
continue;

std::vector<node<Ntk>> leaves;
Expand Down Expand Up @@ -423,7 +435,7 @@ class cut_rewriting_impl
for ( auto& cut : cuts.cuts( ntk.node_to_index( n ) ) )
{
/* skip trivial cuts */
if ( cut->size() <= 2 )
if ( cut->size() < ps.min_cand_cut_size )
continue;

const auto tt = cuts.truth_table( *cut );
Expand Down Expand Up @@ -499,7 +511,7 @@ class cut_rewriting_impl
} );

stopwatch t2( st.time_mis );
auto [g, map] = network_cuts_graph( ntk, cuts, ps.allow_zero_gain );
auto [g, map] = network_cuts_graph( ntk, cuts, ps );

if ( ps.very_verbose )
{
Expand Down
18 changes: 18 additions & 0 deletions include/mockturtle/utils/cuts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ template<int MaxLeaves, typename T = empty_cut_data>
class cut
{
public:
/*! \brief Default constructor.
*/
cut() = default;

/*! \brief Copy constructor.
*
* Copies leaves, length, signature, and data.
*
* \param other Other cut
*/
cut( cut const& other )
{
_cend = _end = std::copy( other.begin(), other.end(), _leaves.begin() );
_length = other._length;
_signature = other._signature;
_data = other._data;
}

/*! \brief Assignment operator.
*
* Copies leaves, length, signature, and data.
Expand Down
41 changes: 41 additions & 0 deletions test/algorithms/cut_enumeration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

#include <iostream>

#include <kitty/constructors.hpp>
#include <kitty/dynamic_truth_table.hpp>
#include <mockturtle/algorithms/cut_enumeration.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/klut.hpp>

using namespace mockturtle;

Expand Down Expand Up @@ -134,3 +137,41 @@ TEST_CASE( "compute truth tables of AIG cuts", "[cut_enumeration]" )
CHECK( cuts.truth_table( cuts.cuts( i4 )[2] )._bits[0] == 0x0d );
CHECK( cuts.truth_table( cuts.cuts( i4 )[3] )._bits[0] == 0x0d );
}

TEST_CASE( "compute XOR network cuts in 2-LUT network", "[cut_enumeration]" )
{
klut_network klut;

const auto a = klut.create_pi();
const auto b = klut.create_pi();

const auto g1 = klut.create_not( a );
const auto g2 = klut.create_and( g1, b );
const auto g3 = klut.create_not( b );
const auto g4 = klut.create_and( a, g3 );

kitty::dynamic_truth_table or_func( 2u );
kitty::create_from_binary_string( or_func, "1110" );
const auto g5 = klut.create_node( {g2, g4}, or_func );
klut.create_po( g5 );

cut_enumeration_params ps;
const auto cuts = cut_enumeration<klut_network, true>( klut, ps );

CHECK( cuts.cuts( g1 ).size() == 2u );
CHECK( cuts.cuts( g3 ).size() == 2u );

for ( auto const& cut : cuts.cuts( g1 ) ) {
CHECK( cut->size() == 1u );
}

for ( auto const& cut : cuts.cuts( g3 ) ) {
CHECK( cut->size() == 1u );
}

for ( auto const& cut : cuts.cuts( g5 ) ) {
if ( cut->size() == 2u && *cut->begin() == 2u ) {
CHECK( cuts.truth_table( *cut )._bits[0] == 0x6u );
}
}
}
12 changes: 8 additions & 4 deletions test/algorithms/quality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ TEST_CASE( "Test quality improvement of cut rewriting with NPN4 resynthesis", "[
return before - ntk.num_gates();
} );

CHECK( v == std::vector<uint32_t>{{0, 20, 80, 49, 160, 79, 199, 131, 506, 2, 258}} );
CHECK( v == std::vector<uint32_t>{{0, 20, 80, 49, 160, 79, 195, 131, 506, 2, 258}} );

// with zero gain
const auto v2 = foreach_benchmark<mig_network>( []( auto& ntk, auto ) {
Expand All @@ -128,7 +128,7 @@ TEST_CASE( "Test quality improvement of cut rewriting with NPN4 resynthesis", "[
return before - ntk.num_gates();
} );

CHECK( v2 == std::vector<uint32_t>{{0, 20, 78, 49, 158, 79, 200, 131, 525, 2, 255}} );
CHECK( v2 == std::vector<uint32_t>{{0, 20, 78, 49, 158, 79, 196, 132, 525, 2, 255}} );
}

TEST_CASE( "Test quality improvement of MIG refactoring with Akers resynthesis", "[quality]" )
Expand Down Expand Up @@ -303,12 +303,14 @@ TEST_CASE( "Test quality improvement of cut rewriting with AIG NPN4 resynthesis"
const auto before = ntk.num_gates();
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4;
ps.min_cand_cut_size = 2;
ps.min_cand_cut_size_override = 3;
cut_rewriting( ntk, resyn, ps );
ntk = cleanup_dangling( ntk );
return before - ntk.num_gates();
} );

CHECK( v == std::vector<uint32_t>{{0, 18, 4, 9, 84, 17, 114, 93, 247, 17, 22}} );
CHECK( v == std::vector<uint32_t>{{0, 17, 4, 9, 60, 16, 113, 93, 250, 17, 21}} );
}

TEST_CASE( "Test quality improvement of cut rewriting with XAG NPN4 resynthesis", "[quality]" )
Expand All @@ -319,12 +321,14 @@ TEST_CASE( "Test quality improvement of cut rewriting with XAG NPN4 resynthesis"
const auto before = ntk.num_gates();
cut_rewriting_params ps;
ps.cut_enumeration_ps.cut_size = 4;
ps.min_cand_cut_size = 2;
ps.min_cand_cut_size_override = 3;
cut_rewriting( ntk, resyn, ps );
ntk = cleanup_dangling( ntk );
return before - ntk.num_gates();
} );

CHECK( v == std::vector<uint32_t>{{0, 38, 200, 62, 248, 124, 236, 174, 487, 561, 409}} );
CHECK( v == std::vector<uint32_t>{{0, 31, 152, 50, 176, 79, 215, 134, 411, 869, 293}} );
}

#endif

0 comments on commit a259f7d

Please sign in to comment.