Skip to content

Commit

Permalink
Use std::stable_sort instead of std::sort everywhere (#655)
Browse files Browse the repository at this point in the history
Test results currently depend on how compare-equal elements are sorted
by `std::sort`'s`unstable sort. Defaulting to `std::stable_sort` avoids
that problem and generally increases the determinism of the code, which
is good.

If there are specific cases where the (fairly small) performance
overhead of stable sorting is a concern, those can be switched back
to unstable sorting as an optimization, but first one would need to
verify that that doesn't break the tests (e.g., by running the tests
with a shuffle before each call to unstable sort).

Resolves #654
  • Loading branch information
rocallahan authored Jul 14, 2024
1 parent 91e15a9 commit ebf35c2
Show file tree
Hide file tree
Showing 33 changed files with 65 additions and 65 deletions.
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aig_balancing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class aig_balance_impl
assert( storage[level].size() > 1 );

/* sort by decreasing level */
std::sort( storage[level].begin(), storage[level].end(), [this]( auto const& a, auto const& b ) {
std::stable_sort( storage[level].begin(), storage[level].end(), [this]( auto const& a, auto const& b ) {
return ntk.level( ntk.get_node( a ) ) > ntk.level( ntk.get_node( b ) );
} );

Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/akers_synthesis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ class unitized_table
}
}

std::sort( to_be_removed.begin(), to_be_removed.end() );
std::stable_sort( to_be_removed.begin(), to_be_removed.end() );
to_be_removed.erase( std::unique( to_be_removed.begin(), to_be_removed.end() ), to_be_removed.end() );

std::reverse( std::begin( to_be_removed ), std::end( to_be_removed ) );
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/aqfp_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ class aqfp_db
auto input_ind = 1u;

auto tmp_input_slots = net.input_slots;
std::sort( tmp_input_slots.begin(), tmp_input_slots.end() );
std::stable_sort( tmp_input_slots.begin(), tmp_input_slots.end() );
assert( tmp_input_slots == net.input_slots );

for ( auto i : net.input_slots )
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/aqfp_fanout_resyn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ struct aqfp_fanout_resyn

auto offsets = balanced_splitter_tree_offsets( ntk_src.fanout_size( n ) );

std::sort( fanouts_n.begin(), fanouts_n.end(), [&]( auto f1, auto f2 ) { return ( ntk_src.depth() - ntk_src.level( f1 ) ) > ( ntk_src.depth() - ntk_src.level( f2 ) ) ||
std::stable_sort( fanouts_n.begin(), fanouts_n.end(), [&]( auto f1, auto f2 ) { return ( ntk_src.depth() - ntk_src.level( f1 ) ) > ( ntk_src.depth() - ntk_src.level( f2 ) ) ||
( ( ntk_src.depth() - ntk_src.level( f1 ) ) == ( ntk_src.depth() - ntk_src.level( f2 ) ) && ( f1 < f2 ) ); } );

auto n_dest = ntk_dest.get_node( f );
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/aqfp_retiming.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ class aqfp_retiming_impl
}
} );

std::sort( classes.begin(), classes.end(), [&]( std::vector<node> const& a, std::vector<node> const& b ) { return a.size() > b.size(); } );
std::stable_sort( classes.begin(), classes.end(), [&]( std::vector<node> const& a, std::vector<node> const& b ) { return a.size() > b.size(); } );

return classes;
}
Expand Down
4 changes: 2 additions & 2 deletions include/mockturtle/algorithms/aqfp/buffer_insertion.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ class buffer_insertion
} );

/* sort by descending order of levels */
std::sort( level_assignment.begin(), level_assignment.end(), std::greater<uint32_t>() );
std::stable_sort( level_assignment.begin(), level_assignment.end(), std::greater<uint32_t>() );

/* simulate splitter tree reconstruction */
uint32_t nodes_in_level = 0;
Expand Down Expand Up @@ -1076,7 +1076,7 @@ class buffer_insertion
}

/* sort by descending order of levels */
std::sort( level_assignment.begin(), level_assignment.end(), []( auto const& a, auto const& b ) {
std::stable_sort( level_assignment.begin(), level_assignment.end(), []( auto const& a, auto const& b ) {
return a[1] > b[1];
} );

Expand Down
8 changes: 4 additions & 4 deletions include/mockturtle/algorithms/aqfp/detail/dag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,16 @@ struct aqfp_dag
{
auto x1 = nodes[i];
auto x2 = rhs.nodes[i];
std::sort( x1.begin(), x1.end() );
std::sort( x2.begin(), x2.end() );
std::stable_sort( x1.begin(), x1.end() );
std::stable_sort( x2.begin(), x2.end() );
if ( x1 != x2 )
return false;
}

auto y1 = input_slots;
auto y2 = rhs.input_slots;
std::sort( y1.begin(), y1.end() );
std::sort( y2.begin(), y2.end() );
std::stable_sort( y1.begin(), y1.end() );
std::stable_sort( y2.begin(), y2.end() );
if ( y1 != y2 )
return false;

Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/detail/dag_cost.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ class dag_aqfp_cost
{
rellev.push_back( lev - curlev[fo] );
}
std::sort( rellev.begin(), rellev.end() );
std::stable_sort( rellev.begin(), rellev.end() );

return fanout_cc( rellev );
}
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/detail/dag_gen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class dags_from_partial_dag
{
std::vector<NodeT> leaves = net.last_layer_leaves;
leaves.insert( leaves.end(), net.other_leaves.begin(), net.other_leaves.end() );
std::sort( leaves.begin(), leaves.end() );
std::stable_sort( leaves.begin(), leaves.end() );

auto max_counts = net.max_equal_fanins();

Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/detail/dag_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ struct sublist_generator
for ( auto i = last_count; i > 0; --i )
{
t.push_back( last_elem );
std::sort( t.begin(), t.end() );
std::stable_sort( t.begin(), t.end() );
result.insert( t );
}
}
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/aqfp/detail/db_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ class aqfp_db_builder
auto input_ind = 1u;

auto tmp_input_slots = net.input_slots;
std::sort( tmp_input_slots.begin(), tmp_input_slots.end() );
std::stable_sort( tmp_input_slots.begin(), tmp_input_slots.end() );
assert( tmp_input_slots == net.input_slots );

for ( auto i : net.input_slots )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ class mig_algebraic_depth_rewriting_splitter_impl
{
std::array<signal<Ntk>, 3> children;
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
std::stable_sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
} );
return children;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct lut_mapping_update_cuts<cut_enumeration_spectr_cut>
}
} );

std::sort( node_to_cut[n].begin(), node_to_cut[n].end() );
std::stable_sort( node_to_cut[n].begin(), node_to_cut[n].end() );
node_to_cut[n].erase( unique( node_to_cut[n].begin(), node_to_cut[n].end() ), node_to_cut[n].end() );
}

Expand Down
4 changes: 2 additions & 2 deletions include/mockturtle/algorithms/emap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5157,7 +5157,7 @@ class emap_impl
class_list.push_back( it );
}

std::sort( class_list.begin(), class_list.end(), [&]( auto const& a, auto const& b ) {
std::stable_sort( class_list.begin(), class_list.end(), [&]( auto const& a, auto const& b ) {
return a.first[2] > b.first[2];
} );

Expand Down Expand Up @@ -5300,7 +5300,7 @@ class emap_impl
}
}

std::sort( order.begin(), order.end(), [&]( size_t a, size_t b ) {
std::stable_sort( order.begin(), order.end(), [&]( size_t a, size_t b ) {
return tts[a] < tts[b];
} );

Expand Down
4 changes: 2 additions & 2 deletions include/mockturtle/algorithms/experimental/cost_resyn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class cost_resyn
{
l.score = kitty::count_ones( ( l.lit & 0x1 ? ~get_div( l.lit >> 1 ) : get_div( l.lit >> 1 ) ) & on_off_sets[on_off] );
}
std::sort( pos_unate_lits.begin(), pos_unate_lits.end(), [&]( unate_lit const& l1, unate_lit const& l2 ) {
std::stable_sort( pos_unate_lits.begin(), pos_unate_lits.end(), [&]( unate_lit const& l1, unate_lit const& l2 ) {
return l1.score > l2.score; // descending order
} );
}
Expand All @@ -221,7 +221,7 @@ class cost_resyn
p.score = ( p.lit1 > p.lit2 ) ? kitty::count_ones( ( ( p.lit1 & 0x1 ? ~get_div( p.lit1 >> 1 ) : get_div( p.lit1 >> 1 ) ) ^ ( p.lit2 & 0x1 ? ~get_div( p.lit2 >> 1 ) : get_div( p.lit2 >> 1 ) ) ) & on_off_sets[on_off] )
: kitty::count_ones( ( p.lit1 & 0x1 ? ~get_div( p.lit1 >> 1 ) : get_div( p.lit1 >> 1 ) ) & ( p.lit2 & 0x1 ? ~get_div( p.lit2 >> 1 ) : get_div( p.lit2 >> 1 ) ) & on_off_sets[on_off] );
}
std::sort( unate_pairs.begin(), unate_pairs.end(), [&]( fanin_pair const& p1, fanin_pair const& p2 ) {
std::stable_sort( unate_pairs.begin(), unate_pairs.end(), [&]( fanin_pair const& p1, fanin_pair const& p2 ) {
return p1.score > p2.score; // descending order
} );
}
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/lut_mapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2172,7 +2172,7 @@ class lut_map_impl
}

/* sort leaves in topo order */
std::sort( leaves.begin(), leaves.end() );
std::stable_sort( leaves.begin(), leaves.end() );

ntk.add_to_mapping( n, leaves.begin(), leaves.end() );

Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/mig_algebraic_rewriting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ class mig_algebraic_depth_rewriting_impl
{
std::array<signal<Ntk>, 3> children;
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
std::stable_sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
} );
return children;
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/reconv_cut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ class reconvergence_driven_cut_impl2
bool construct_cut()
{
assert( leaves.size() <= ps.max_leaves && "cut-size overflow" );
std::sort( std::begin( leaves ), std::end( leaves ),
std::stable_sort( std::begin( leaves ), std::end( leaves ),
[this]( node const& a, node const& b ) {
return cost( a ) < cost( b );
} );
Expand Down
4 changes: 2 additions & 2 deletions include/mockturtle/algorithms/resyn_engines/xag_resyn.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ class xag_resyn_decompose
{
l.score = kitty::count_ones( ( l.lit & 0x1 ? ~get_div( l.lit >> 1 ) : get_div( l.lit >> 1 ) ) & on_off_sets[on_off] );
}
std::sort( unate_lits.begin(), unate_lits.end(), [&]( unate_lit const& l1, unate_lit const& l2 ) {
std::stable_sort( unate_lits.begin(), unate_lits.end(), [&]( unate_lit const& l1, unate_lit const& l2 ) {
return l1.score > l2.score; // descending order
} );
}
Expand All @@ -595,7 +595,7 @@ class xag_resyn_decompose
p.score = kitty::count_ones( ( p.lit1 & 0x1 ? ~get_div( p.lit1 >> 1 ) : get_div( p.lit1 >> 1 ) ) & ( p.lit2 & 0x1 ? ~get_div( p.lit2 >> 1 ) : get_div( p.lit2 >> 1 ) ) & on_off_sets[on_off] );
}
}
std::sort( unate_pairs.begin(), unate_pairs.end(), [&]( fanin_pair const& p1, fanin_pair const& p2 ) {
std::stable_sort( unate_pairs.begin(), unate_pairs.end(), [&]( fanin_pair const& p1, fanin_pair const& p2 ) {
return p1.score > p2.score; // descending order
} );
}
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/xag_balancing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class xag_balance_impl
assert( storage[level].size() > 1 );

/* sort by decreasing level */
std::sort( storage[level].begin(), storage[level].end(), [this]( auto const& a, auto const& b ) {
std::stable_sort( storage[level].begin(), storage[level].end(), [this]( auto const& a, auto const& b ) {
return ntk.level( ntk.get_node( a ) ) > ntk.level( ntk.get_node( b ) );
} );

Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/xmg_algebraic_rewriting.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ class xmg_algebraic_depth_rewriting_impl
{
std::array<signal<Ntk>, 3> children;
ntk.foreach_fanin( n, [&children]( auto const& f, auto i ) { children[i] = f; } );
std::sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
std::stable_sort( children.begin(), children.end(), [this]( auto const& c1, auto const& c2 ) {
return ntk.level( ntk.get_node( c1 ) ) < ntk.level( ntk.get_node( c2 ) );
} );
return children;
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/algorithms/xmg_resub.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ struct xmg_resub_functor
auto const& tt_s = sim.get_tt( s );
sorted_divs.emplace_back( static_cast<uint32_t>( *it ), static_cast<uint32_t>( relative_distinguishing_power( tt_s, tt ) ) );
}
std::sort( std::rbegin( sorted_divs ), std::rend( sorted_divs ),
std::stable_sort( std::rbegin( sorted_divs ), std::rend( sorted_divs ),
[&]( auto const& u, auto const& v ) {
if ( u.entropy == v.entropy )
return u.node < v.node;
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/generators/self_dualize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ inline aig_network self_dualize_aig( aig_network const& src_aig )

src_aig.foreach_po( [&]( const auto& f ) {
auto leaves = cut_generator.run( { src_aig.get_node( f ) } ).first;
std::sort( std::begin( leaves ), std::end( leaves ) );
std::stable_sort( std::begin( leaves ), std::end( leaves ) );

/* check if all leaves are pis */
for ( const auto& l : leaves )
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/networks/aqfp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ class aqfp_network
return children[0u];
}

std::sort( children.begin(), children.end(), []( auto f, auto s ) { return f.index < s.index; } );
std::stable_sort( children.begin(), children.end(), []( auto f, auto s ) { return f.index < s.index; } );

for ( auto i = 1u; i < children.size(); i++ )
{
Expand Down
4 changes: 2 additions & 2 deletions include/mockturtle/properties/aqfpcost.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class fanout_net_cost

std::vector<uint32_t> new_config( config.begin(), config.begin() + ( config.size() - size ) );
new_config.push_back( sp_lev );
std::sort( new_config.begin(), new_config.end() );
std::stable_sort( new_config.begin(), new_config.end() );

temp += cost_for_config( new_config, ignore_initial_buffers );

Expand Down Expand Up @@ -209,7 +209,7 @@ struct aqfp_network_cost

if ( rellev.size() > 1u || ( rellev.size() == 1u && rellev[0] > 0 ) )
{
std::sort( rellev.begin(), rellev.end() );
std::stable_sort( rellev.begin(), rellev.end() );
auto net_cost = fanout_cc( rellev, ntk.is_ci( n ) && !assume.balance_pis );
if ( net_cost == std::numeric_limits<double>::infinity() )
{
Expand Down
2 changes: 1 addition & 1 deletion include/mockturtle/utils/struct_library.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ class struct_library
uint32_t shift = 0;

/* sort cells by increasing order of area */
std::sort( indexes.begin(), indexes.end(),
std::stable_sort( indexes.begin(), indexes.end(),
[&]( auto const& a, auto const& b ) -> bool {
return _supergates[a].area < _supergates[b].area;
} );
Expand Down
8 changes: 4 additions & 4 deletions include/mockturtle/utils/tech_library.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,15 +816,15 @@ class tech_library

std::iota( order.begin(), order.end(), 0 );

std::sort( order.begin(), order.end(), [&]( size_t a, size_t b ) {
std::stable_sort( order.begin(), order.end(), [&]( size_t a, size_t b ) {
return static_tts[a] < static_tts[b];
} );

std::transform( order.begin(), order.end(), sorted_tts.begin(), [&]( size_t a ) {
return static_tts[a];
} );

// std::sort( static_tts.begin(), static_tts.end() );
// std::stable_sort( static_tts.begin(), static_tts.end() );

auto& v = _multi_lib[sorted_tts];

Expand Down Expand Up @@ -1406,14 +1406,14 @@ class exact_library
rewriting_fn( _database, function, pis.begin(), pis.end(), add_supergate );
if ( supergates_pos.size() > 0 )
{
std::sort( supergates_pos.begin(), supergates_pos.end(), [&]( auto const& a, auto const& b ) {
std::stable_sort( supergates_pos.begin(), supergates_pos.end(), [&]( auto const& a, auto const& b ) {
return a.area < b.area;
} );
_super_lib.insert( { entry, supergates_pos } );
}
if ( _ps.np_classification && supergates_neg.size() > 0 )
{
std::sort( supergates_neg.begin(), supergates_neg.end(), [&]( auto const& a, auto const& b ) {
std::stable_sort( supergates_neg.begin(), supergates_neg.end(), [&]( auto const& a, auto const& b ) {
return a.area < b.area;
} );
_super_lib.insert( { not_entry, supergates_neg } );
Expand Down
12 changes: 6 additions & 6 deletions include/mockturtle/utils/window_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector<typename Ntk::nod
}
}

std::sort( std::begin( used ), std::end( used ) );
std::stable_sort( std::begin( used ), std::end( used ) );

for ( uint32_t index = 0u; index < used.size(); ++index )
{
Expand Down Expand Up @@ -761,7 +761,7 @@ void levelized_expand_towards_tfo( Ntk const& ntk, std::vector<typename Ntk::nod
if ( std::find( std::begin( used ), std::end( used ), node_level ) == std::end( used ) )
{
used.push_back( node_level );
std::sort( std::begin( used ), std::end( used ) );
std::stable_sort( std::begin( used ), std::end( used ) );
}
}

Expand Down Expand Up @@ -841,7 +841,7 @@ std::vector<typename Ntk::node> cover( Ntk const& ntk, typename Ntk::node const&
detail::cover_recursive( ntk, root, nodes );

/* remove duplicates */
std::sort( std::begin( nodes ), std::end( nodes ) );
std::stable_sort( std::begin( nodes ), std::end( nodes ) );
auto last = std::unique( std::begin( nodes ), std::end( nodes ) );
nodes.erase( last, std::end( nodes ) );

Expand Down Expand Up @@ -923,7 +923,7 @@ class create_window_impl
*nodes = cover( ntk, pivot, inputs );

/* expand the nodes towards the TFO */
std::sort( std::begin( inputs ), std::end( inputs ) );
std::stable_sort( std::begin( inputs ), std::end( inputs ) );
detail::levelized_expand_towards_tfo( ntk, inputs, *nodes, levels );
}

Expand All @@ -933,8 +933,8 @@ class create_window_impl
}

/* top. sort nodes */
std::sort( std::begin( inputs ), std::end( inputs ) );
std::sort( std::begin( *nodes ), std::end( *nodes ) );
std::stable_sort( std::begin( inputs ), std::end( inputs ) );
std::stable_sort( std::begin( *nodes ), std::end( *nodes ) );

/* collect the nodes with fanout outside of nodes */
std::vector<signal> outputs = collect_outputs( ntk, inputs, *nodes, refs );
Expand Down
4 changes: 2 additions & 2 deletions include/mockturtle/views/mffc_view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,9 @@ class mffc_view : public immutable_view<Ntk>

void compute_sets()
{
// std::sort( _nodes.begin(), _nodes.end(),
// std::stable_sort( _nodes.begin(), _nodes.end(),
// [&]( auto const& n1, auto const& n2 ) { return static_cast<Ntk*>( this )->node_to_index( n1 ) < static_cast<Ntk*>( this )->node_to_index( n2 ); } );
std::sort( _nodes.begin(), _nodes.end() );
std::stable_sort( _nodes.begin(), _nodes.end() );

for ( auto const& n : _nodes )
{
Expand Down
Loading

0 comments on commit ebf35c2

Please sign in to comment.